MySQL - query for sorting - mysql

Example data:
username score time
-------- ----- ----
jim 90 50
jim 90 30
paul 50 30
bob 100 90
tim 90 20
I want to be able to sort by score in descending order. If two scores are the same, sort by the lowest time. If there are multiple rows with the same username, I only want one. So the above table should look like this:
username score time
-------- ----- ----
bob 100 90
tim 90 20
jim 90 30
paul 50 30
I have a query that nearly produces this, however, if the scores are the same, it doesn't sort by lowest time. How would I do this?
SELECT U.username, S.score, S.time
FROM scores S JOIN users U ON S.user_id=U.user_id
WHERE NOT EXISTS (
SELECT 1 FROM scores R2 WHERE R2.user_id = S.user_id and R2.score_id > S.score_id
)
AND test_id=0
AND module_id=1
ORDER BY score DESC, time ASC;

Avoiding using a sub query and using a LEFT OUTER JOIN instead.:-
SELECT U.username, s1.score, s1.time
FROM scores s1
INNER JOIN users U
ON s1.user_id = U.user_id
LEFT OUTER JOIN scores s2
ON s1.user_id = s2.user_id
AND (s1.score < s2.score
OR (s1.score = s2.score
AND s1.time > s2.time))
WHERE s2.user_id IS NULL
ORDER BY s1.score DESC, s1.time ASC
This does a LEFT OUTER JOIN against the score table looking for a match for the same user with a higher score, or the same score and a faster time. Any where these are found are not the best score so are dropped with the WHERE clause
SQL fiddle for this:-
http://sqlfiddle.com/#!2/7f3e93/3
Edit - adding the test_id and module_id checks if required:-
SELECT U.username, s1.score, s1.time
FROM scores s1
INNER JOIN users U
ON s1.user_id = U.user_id
LEFT OUTER JOIN scores s2
ON s1.user_id = s2.user_id
AND s2.test_id = 0
AND s2.module_id = 1
AND (s1.score < s2.score
OR (s1.score = s2.score
AND s1.time > s2.time))
WHERE s2.user_id IS NULL
AND s1.test_id = 0
AND s1.module_id = 1
ORDER BY s1.score DESC, s1.time ASC

SELECT U.username, max(S.score) as maxscore, min(S.time) as mintime
FROM scores S
JOIN users U ON S.user_id=U.user_id
WHERE NOT EXISTS
(
SELECT 1 FROM scores R2
WHERE R2.user_id = S.user_id and R2.score_id > S.score_id
)
AND test_id=0
AND module_id=1
GROUP BY U.username
ORDER BY maxscore DESC, mintime ASC;

Related

combining two select statements with group by and order by

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;

SQL join and sum of items

There are two tables
users
+--+----+
|id|name|
+--+----+
1 A
2 B
orders
+--+--------+-------+-------+
|id|subtotal|created|user_id|
+--+--------+-------+-------+
1 10 1000001 1
2 20 1000002 1
3 10 1000003 2
4 10 1000005 1
The idea is to get AVG, SUM and the last created order from the users.
SELECT
users.name,
users.phone,
SUM(a.subtotal),
COALESCE(a.created, NULL)
FROM users
LEFT JOIN
(
SELECT
orders.id,
orders.subtotal,
orders.user_id,
orders.created
FROM
orders
JOIN(
SELECT MAX(i.created) created, i.user_id
FROM orders i
GROUP BY i.user_id
)AS j ON(j.user_id = orders.user_id AND orders.created = j.created) GROUP BY orders.user_id
) AS a ON users.id = a.user_id
GROUP BY users.id
For example the SQL request should return this:
+--+----+---+--------+
|id|name|sum|date |
+--+----+---+--------+
1 A 40 1000005
2 B 10 1000003
But the SQL above failed to calculate sum. What did i miss?
Your query seems way too complicated. How about this?
SELECT u.id, u.name, SUM(o.subtotal), MAX(o.created)
FROM users u LEFT JOIN
orders o
ON u.id = o.user_id
GROUP BY u.id, u.name;
In MySQL it is particularly important to avoid unnecessary subqueries in the FROM clause. These are actually materialized and that can impede the use of indexes for performance.

Merge 2 SQL Queries/Tables

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;

Mysql query returns duplicate entry

SELECT *
FROM ( SELECT a.*, a.id AS id_player,
(SELECT COUNT(id)
FROM `vd7qw_footsal_goals`
WHERE a.id = id_player
AND id_group IN (SELECT id_group
from `vd7qw_footsal_groupofleague`
WHERE id_league = 2)
) AS goals,
team.team_name
FROM `vd7qw_footsal_players` AS a
LEFT JOIN vd7qw_footsal_teams AS team
ON team.id = a.id_team
LEFT JOIN vd7qw_footsal_teamofgroup AS tog
ON tog.id_team = team.id
LEFT JOIN vd7qw_footsal_groups AS g
ON g.id = tog.id_group
WHERE (a.state IN (1))
) AS h
WHERE goals > 0
ORDER BY goals DESC
This is my query when I have 2 or more groups in 1 league and player score a goal in each group, query returns the correct number of goals but duplicates player for example:
John Doe got 3 goals in group 1
and
John Doe got 4 goals in group 2
Query returns:
John Doe got 7 goals
where is my mistake?
Try GROUP BY
SELECT *
FROM ( SELECT a.*, a.id AS id_player, (SELECT COUNT(id)
FROM `vd7qw_footsal_goals`
WHERE a.id = id_player
AND id_group IN (SELECT id_group
from `vd7qw_footsal_groupofleague`
WHERE id_league = 2)) AS goals, team.team_name
FROM `vd7qw_footsal_players` AS a
LEFT JOIN vd7qw_footsal_teams AS team
ON team.id = a.id_team
LEFT JOIN vd7qw_footsal_teamofgroup AS tog
ON tog.id_team = team.id
LEFT JOIN vd7qw_footsal_groups AS g
ON g.id = tog.id_group
WHERE (a.state IN (1))) AS h
WHERE goals > 0
GROUP BY id_group
ORDER BY goals DESC

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

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