My Query:
SET #rank = 0;
SELECT Jobs.ID, Jobs.StatusID, (#rank:=#rank+1) AS Rank
FROM Jobs
INNER JOIN JobStatuses ON Jobs.StatusID = JSID
INNER JOIN JobStatusGroups ON Jobs.SGrID = JSGID
WHERE Jobs.StatusID = 3
ORDER BY JobTitle DESC
LIMIT 5
Results in:
1010 3 1
1011 3 2
1013 3 4
1014 3 5
1016 3 7
Should result in:
1010 3 1
1011 3 2
1013 3 3
1014 3 4
1016 3 5
How can I make #rank only increment if row is actually being inserted? I tried cross join did not work. I also tried the following:
SELECT Jobs.ID, Jobs.StatusID, (#rank:=#rank+1) AS Rank
FROM Jobs, (SELECT #rank := 0) tempRank
INNER JOIN JobStatuses ON Jobs.StatusID = JSID
INNER JOIN JobStatusGroups ON Jobs.SGrID = JSGID
WHERE Jobs.StatusID = 3
ORDER BY JobTitle DESC
LIMIT 5
But gives me an error saying Jobs.StatusID does not exist.
instead of setting it outside cross join it in the select (i prefer cross join just so its easier to read aka i know where im creating the variable) that way the count wont be messed up
INSERT IGNORE INTO MyTable(MyID, UserID, JobID, StatusID, SortOrder)
SELECT :myid, :userid, Jobs.ID, Jobs.StatusID, (#rank:=#rank+1) AS Rank
FROM Jobs
INNER JOIN JobStatuses ON Jobs.StatusID = JSID
CROSS JOIN (SELECT #rank := 0) temp
LEFT JOIN JobStatusGroups ON Jobs.SGrID = JSGID
WHERE ...
ORDER BY JobTitle DESC
on terms of performance I haven't ever noticed performance issues with using the variables instantiation inside a join on the table
one thing you can try is maybe the ORDER BY is messing up the order / count so you can try encapsulating it in a subselect
SELECT ID, StatusID, (#rank:=#rank+1) AS Rank
FROM
( SELECT Jobs.ID, Jobs.StatusID
FROM Jobs
INNER JOIN JobStatuses ON Jobs.StatusID = JSID
INNER JOIN JobStatusGroups ON Jobs.SGrID = JSGID
WHERE Jobs.StatusID = 3
ORDER BY JobTitle DESC
LIMIT 5
)t
CROSS JOIN (SELECT #rank := 0) temp
Try This updated one:
SET #rank = 0;
INSERT INTO MyTable(MyID, UserID, JobID, StatusID, SortOrder)
SELECT myid, userid, Jobs.ID, Jobs.StatusID, (#rank:=#rank+1) AS Rank
FROM Jobs
INNER JOIN JobStatuses ON Jobs.StatusID = JobStatuses.JSID
LEFT JOIN JobStatusGroups ON Jobs.SGrID = JobStatusGroups.JSGID
ON DUPLICATE KEY update MyID=IF((#rank:=#rank-1) <> NULL IS NULL, VALUES(MyID), NULL);
Related
I have a problem here, I wonder if it is possible to do this in just one query instead of having the server do several queries.
So here's the thing, what I want is, in each category, to search all stores belonging to that category within a limit of 24 stores. That is, imagining that I have 5 categories registered, I will search 24 stores belonging to that category, which in the conclusion I will have a total of 120 stores in the query result.
The following code is an example, but this will only fetch the first 24 stores of any category without iterating through each category.
SELECT *
FROM categories c
LEFT JOIN (SELECT * FROM stores_categories LIMIT 24 OFFSET 0) sc ON sc.id_category = c.id
WHERE type = 'STORE' OR type = 'ALL';
Someone sent me this and it is very similar to my problem, How to SELECT the newest four items per category?, It is kind of like that, but I would like to be able to limit and with offset to make pages and not just the first 24 most recent in each category.
The example code from the link I was given:
SELECT sc1.*
FROM stores_categories sc1
LEFT OUTER JOIN stores_categories sc2 ON (sc1.id_category = sc2.id_category AND sc1.id_store < sc2.id_store)
GROUP BY sc1.id_store
HAVING COUNT(*) < 24
ORDER BY sc1.id_category;
And the database server which one I'm is the version 5.5.64-MariaDB. An fiddle example where is possible to make tests with same values from my database. https://www.db-fiddle.com/f/jcowJL9S4FQXqKg2yMa8kf/0
It could make use of a calculated row_number per category.
--
-- Emulated row_number via variables
--
SELECT sc.id, id_store
, cat.name AS cat_name
, cat.type AS cat_type
, rn
FROM
(
SELECT sc.*
, #rn := CASE
WHEN #cat_id = sc.id_category
THEN #rn + 1 ELSE 1
END AS rn
, #cat_id := sc.id_category as cat_id
FROM stores_categories sc
CROSS JOIN (SELECT #cat_id:=0, #rn:=0) vars
ORDER BY sc.id_category, sc.id_store DESC, sc.id DESC
) sc
LEFT JOIN categories cat
ON cat.id = sc.id_category
WHERE rn BETWEEN 1 AND 24
ORDER BY sc.id_category, sc.id_store DESC, sc.id DESC
Or
--
-- Grouped self-join
--
SELECT sc.id, sc.id_store
, cat.name AS cat_name
, cat.type AS cat_type
, COUNT(sc2.id_store) AS cnt
FROM stores_categories sc
LEFT JOIN stores_categories sc2
ON sc2.id_category = sc.id_category
AND sc2.id_store >= sc.id_store
LEFT JOIN categories cat
ON cat.id = sc.id_category
GROUP BY sc.id
HAVING cnt BETWEEN 1 AND 24
ORDER BY sc.id_category, sc.id_store DESC;
Or
--
-- Correlated sub-query
--
SELECT sc.id, id_store
, cat.name AS cat_name
, cat.type AS cat_type
, ( select count(*)
from stores_categories sc2
where sc2.id_category = sc.id_category
and sc2.id_store >= sc.id_store
) as rn
FROM stores_categories AS sc
LEFT JOIN categories cat
ON cat.id = sc.id_category
HAVING rn BETWEEN 1 AND 24
ORDER BY sc.id_category, sc.id_store DESC;
Demo on db<>fiddle here
I have the following 2 select statements that work and return the info on their own, but was wondering if there was a way to join / combine them into one report with their own separate rows and columns
Select Sum (amount) as PDCGross
From Desk D Left Join
Master M
on D.code = M.desk INNER JOIN
pdc
ON m.number = pdc.number
Where teamid = 3
AND active = 1
And onhold is NULL
And deposit >='2020-10-01'
And deposit <= '2020-10-31'
Group by D.Name
Order by desk.Name Desc
Select Sum (amount) as GrossPDCC
FROM Desk D left JOIN
Master M
on D.code = M.Desk INNER JOIN
DebtorCreditCards P
ON m.number = P.Number
Where teamid = 3
AND IsActive = 1
And OnHoldDate is NULL
And DepositDate >='2020-10-01'
And DepositDate <= '2020-10-31'
Group by D.Name
Order by desk.Name Desc
The return for the 1st statement
PDCPross
2500
1500
1300
The result of the 2nd statement is
PDCCGross
1500
1300
1000
What i am looking for is
PDCPross PDCCGross
2500 1500
1500 1300
1300 1000
On MySQL v 8.0+ or MariaDB 10.2 +, you can use ROW_NUMBER() function:
Assign each query with ROW_NUMBER() then make both query as sub-query. Join the queries using the rownum result and you should be able to see your results side by side. Something like this query example:
SELECT A.PDCGross, B.GrossPDCC FROM
(SELECT ROW_NUMBER() OVER (ORDER BY D.Name DESC) AS rownum, SUM(amount) AS PDCGross
FROM Desk D LEFT JOIN
MASTER M
ON D.code = M.desk INNER JOIN
pdc
ON m.number = pdc.number
WHERE teamid = 3
AND active = 1
AND onhold IS NULL
AND deposit >='2020-10-01'
AND deposit <= '2020-10-31'
GROUP BY D.Name
ORDER BY D.Name DESC) A JOIN
(SELECT ROW_NUMBER() OVER (ORDER BY D.Name DESC) AS rownum, SUM(amount) AS GrossPDCC
FROM Desk D LEFT JOIN
MASTER M
ON D.code = M.Desk INNER JOIN
DebtorCreditCards P
ON m.number = P.Number
WHERE teamid = 3
AND IsActive = 1
AND OnHoldDate IS NULL
AND DepositDate >='2020-10-01'
AND DepositDate <= '2020-10-31'
GROUP BY D.Name
ORDER BY D.Name DESC) B ON A.rownum=B.rownum;
I want to rank the total stats of a group of users and assign a rank variable to them.
I used this thread for the Rank variable.
This is my Query atm:
SELECT #rank := #rank + 1 AS rank
, SUM(stats.points) AS x
FROM
( SELECT #rank := 0 ) r
, groups
LEFT
JOIN user_group
ON groups.id = user_groups.clan
LEFT
JOIN stats
ON user_groups.user = stats.id
GROUP
BY groups.id
ORDER
BY x DESC
RANK | points
--------------
47 | 3400
1 | 2500
75 | 1200
As you can see the Sorting by Points works fine, but the Rank variable seems to just pick random values.
Can anyone find a way to assign the rank correctly?
Use a subquery for the aggregation and ordering:
SELECT id, sum_points, #rank := #rank + 1 AS rank
FROM (SELECT g.id, SUM(s.points) AS sum_points
FROM groups g LEFT JOIN
user_group ug
ON g.id = ug.clan LEFT JOIN
stats s
ON ug.user = s.id
GROUP BY g.id
ORDER BY sum_points DESC
) s CROSS JOIN
(SELECT #rank := 0) params;
This has been an issue in MySQL for a while -- variables don't work well with aggregation and ordering.
Note that in MySQL 8+, this is much more simply written as:
SELECT g.id, SUM(s.points) AS sum_points,
ROW_NUMBER() OVER (ORDER BY SUM(s.points) DESC) as rank
FROM groups g LEFT JOIN
user_group ug
ON g.id = ug.clan LEFT JOIN
stats s
ON ug.user = s.id
GROUP BY g.id
I spent so much time googling today but i don't even know which keywords to use. So …
The project is an evaluation of a betting game (Football). I have 2 SQL Queries:
SELECT players.username, players.userid, matchdays.userid, matchdays.points, SUM(points) AS gesamt
FROM players INNER JOIN matchdays ON players.userid = matchdays.userid AND matchdays.season_id=5
GROUP BY players.username
ORDER BY gesamt DESC
And my second query:
SELECT max(matchday) as lastmd, points, players.username from players INNER JOIN matchdays ON players.userid = matchdays.userid WHERE matchdays.season_id=5 AND matchday=
(select max(matchday) from matchdays)group by players.username ORDER BY points DESC
The first one adds up the points of every matchday and shows the sum.
The second shows the points of the last gameday.
My Goal is to merge those 2 queries/tables so that the output is a table like
Rank | Username | Points last gameday | Overall points |
I don't even know where to start or what to look for. Any help would be appreciated ;)
use both query with join....use inner join if each userid have value in 2nd query also.also add userid in 2nd query also for join
SET #rank = 0;
SELECT #rank := rank + 1,
t1.username,
t2.points,
t1.gesamt
FROM (
SELECT players.username, players.userid puserid, matchdays.userid muserid, matchdays.points, SUM(points) AS gesamt
FROM players INNER JOIN matchdays ON players.userid = matchdays.userid AND matchdays.season_id=5
GROUP BY players.username
)t1
INNER JOIN
(
SELECT players.userid, max(matchday) as lastmd, points, players.username
from players INNER JOIN matchdays ON players.userid = matchdays.userid
WHERE matchdays.season_id=5 AND matchday=
(select max(matchday) from matchdays)group by players.username
)t2
ON t1.puserid = t2.userid
ORDER BY t1.gesamt
You can use conditional aggregation, i.e. sum the points only when the day is the last day:
SELECT
p.username,
SUM(case when m.matchday = (select max(matchday) from matchdays) then m.points end)
AS last_day_points,
SUM(m.points) AS total_points
FROM players p
INNER JOIN matchdays m ON p.userid = m.userid AND m.season_id = 5
GROUP BY p.userid
ORDER BY total_points DESC;
Or with a join instead of a non-correlated subquery (MySQL should come to the same execution plan):
SELECT
p.username,
SUM(case when m.matchday = last_day.matchday then m.points end) AS last_day_points,
SUM(m.points) AS total_points
FROM players p
INNER JOIN matchdays m ON p.userid = m.userid AND m.season_id = 5
CROSS JOIN
(
select max(matchday) as matchday
from matchdays
) last_day
GROUP BY p.userid
ORDER BY total_points DESC;
I have social application let's say like twitter, where user can follow other users and can likes some comments.
What I need to fetch is followers of a user and ids of last 2 comments liked by each follower(if any), also the count of follower's followers, using MySQL.
Here are the tables
Table user_follower
User_id follower_id
1 2
2 3
1 5
1 6
1 7
Table user_likes
comment_id User_id date
41 2 some_date
42 2 some_date
41 5 some_date
42 5 some_date
43 5 some_date
43 2 some_date
43 6 some_date
how can we do this in a single mysql query?
so far i am able to get the followers and count of follower's follower and following both.
select uf.follower_id,
(select count(*) from user_followers uf1 where uf1.follower_id = uf.follower_id) as following_count,
(select count(*) from user_followers uf2 where uf2.user_id = uf.follower_id) as follower_count,
from user_followers uf
join users u on u.id = uf.follower_id
where uf.user_id = 1
what i want is now to get the 2 latest comment_ids for each follower, i.e. uf.follower_id here.
if not possible in the same query,
i am fine even with another query as will passing the follower_ids as in parameter, but it should give me 2 latest comment for each passed id..
I think this will work. I have not tested it so it may have some syntax errors. Given the level of nesting used in this query I suspect it will perform badly with a very large dataset.
SELECT follower_id, num_followers, GROUP_CONCAT(comment_id)
FROM (
SELECT t.*,
#r := IF(#g = t.follower_id, #r+1, 1) RowNum,
#g := t.follower_id
FROM (select #g:=null) AS initvars
INNER JOIN (
SELECT followers.*, ul.comment_id
FROM (
SELECT
uf1.user_id,
uf1.follower_id,
COUNT(uf2.follower_id) AS num_followers
FROM user_follower uf1
LEFT JOIN user_follower uf2
ON uf1.follower_id = uf2.user_id
WHERE uf1.user_id = 1
GROUP BY uf1.user_id, uf1.follower_id
) AS followers
LEFT JOIN user_likes ul
ON followers.follower_id = ul.user_id
ORDER BY followers.follower_id ASC, comment_id DESC
) AS t
) AS final
WHERE RowNum < 3
GROUP BY follower_id, num_followers;
UPDATE Here is the other query using the inequality join -
SELECT tmp.follower_id, COUNT(uf2.follower_id) AS num_followers, tmp.comments
FROM (
SELECT follower_id, GROUP_CONCAT(comment_id ORDER BY comment_id DESC) AS comments
FROM (
SELECT uf.follower_id, ul1.*
FROM user_follower uf
LEFT JOIN user_likes ul1
ON uf.follower_id = ul1.user_id
LEFT JOIN user_likes ul2
ON uf.follower_id = ul2.user_id
AND ul1.comment_id < ul2.comment_id
WHERE uf.user_id = 1
GROUP BY ul1.user_id, ul1.comment_id
HAVING COUNT(ul2.comment_id) < 2
) AS tmp
GROUP BY tmp.follower_id
) AS tmp
LEFT JOIN user_follower uf2
ON tmp.follower_id = uf2.user_id
GROUP BY tmp.follower_id