MySQL group by with max value - mysql

Hi I have this table.
id lat lng userId
1 12 23 1
2 45 34 2
3 42 34 3
4 33 34 1
5 36 79 2
6 53 98 2
7 23 90 3
8 23 67 1
Here we have three users. (user ids 1,2,3). I want to get lateset record (id column max value) of each user.
My excepted output is this
userId lat lng
1 23 67
2 53 98
3 23 90
This query will give me group by option
SELECT
*
FROM
covid.locations
GROUP BY userId;
But how do I combine this with MAX(id) function.

One way is to use the following:
SELECT
cl.*
FROM covid.locations cl
INNER JOIN (
SELECT
userid
, MAX( id ) mid
FROM covid.locations
GROUP BY
userId
) g ON cl.userid = g.userid
AND cl.id = cl.mid
Another is to use row_number() over()
SELECT
userId
, lat
, lng
FROM (
SELECT
*
, ROW_NUMBER() OVER (PARTITION BY userid ORDER BY id DESC) rn
FROM covid.locations
GROUP BY
userId
) d
WHERE rn = 1
Both will identify the "most recent" row in the source table based in the id column of that table. Note that the second query requires MySQL version 8+ as this is when row_number() became supported in that database. The first query should run in dbms supporting SQL.

This will do
SELECT
*
FROM
covid.locations
where id in (select max(t.id) from covid.locations t group by t.userId)
order by id desc;
An example of the above query can be found in this SQLFiddle

Related

Select only unique ids row of table with different values in Descending order

I'm trying to get data that have the same medicine_id and unique insurance_id and last inserted row. Put Group by and Order by but in that got random data not last inserted.
I tried this code but got not last inserted data
SELECT
`m1`.`*`
FROM
(
`pricings` `m1`
LEFT JOIN `pricings` `m2` ON
(
(
(
`m1`.`medicine_id` = `m2`.`medicine_id`
)
)
)
)
WHERE m1.medicine_id = 2
group BY m1.insurance_id DESC
ORDER BY m1.created_at;
Here are the total rows.
This is a full table
id
medicine_id
insurance_id
created_at
4311
2
1
2021-04-12 16:05:07
4766
2
1
2022-01-15 11:56:06
4767
2
38
2021-05-12 08:17:11
7177
2
38
2022-03-30 10:14:11
4313
2
39
2021-04-12 16:05:46
4768
2
39
2021-05-12 08:17:30
1356
2
40
2020-11-02 11:25:43
3764
2
40
2021-03-08 15:42:16
4769
2
40
2021-05-12 08:17:44
And I want to like this
id
medicine_id
insurance_id
created_at
4766
2
1
2022-01-15 11:56:06
4768
2
39
2021-05-12 08:17:30
4769
2
40
2021-05-12 08:17:44
7177
2
38
2022-03-30 10:14:11
MySQL 5.x: Use a sub-query to find the max created_at value per group, then join that on the source table to identify the row it was from.
SELECT
p.`*`
FROM
`pricings` p
INNER JOIN
(
SELECT
`medicine_id`,
`insurance_id`,
MAX(created_at) AS `created_at`
FROM
`pricings`
GROUP BY
`medicine_id`,
`insurance_id`
)
p_max
ON p.`medicine_id` = p_max.`medicine_id`
AND p.`insurance_id` = p_max.`insurance_id`
AND p.`created_at` = p_max.`created_at`
WHERE
p.`medicine_id` = 2
ORDER BY
p.`created_at`;
MySQL 8: Use ROW_NUMBER() to enumerate each group, then pick the first row from each group.
SELECT
p.`*`
FROM
`pricings` p
FROM
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY `medicine_id`,
`insurance_id`
ORDER BY `created_at` DESC
)
AS `row_id`
FROM
`pricings`
)
p
WHERE
p.`medicine_id` = 2
AND p.`row_id` = 1
ORDER BY
p.`created_at`;
Adding it as an answer as well. I have not tested it, just fix the formating to work with whatever version of databse you are working with and let me know of the results.
SELECT m1.id , m1.Insurance_id , m1.medicine_id , max(m1,created_at)
FROM (
`pricings` `m1` LEFT JOIN `pricings` `m2` ON `m1`.`medicine_id` = `m2`.`medicine_id`
)
WHERE m1.medicine_id = 2 and m1.insurance_id in (1,39,40,38)
GROUP BY m1.insurance_id DESC
ORDER BY m1.created_at;
Edit. I also removed the 6 extra parenthesis, I don't see how they could be of any use

Select multiple tables with only unique users and ordered by latest id

I have 2 tables, first one is called members:
id name show
1 John 1
2 Wil 1
3 George 1
4 Chris 1
Second is called score:
id user_id score
1 1 90
2 1 70
3 2 55
4 3 30
5 3 40
6 3 100
7 4 30
user_id from score is the id of members.
What I want is to show a scorelist with unique members.id, ordered by score.score and order by the latest score.id.
I use the following code:
SELECT members.id, members.show, score.id, score.user_id, score.score FROM members
INNER JOIN score ON score.user_id = members.id
WHERE members.show = '1'
GROUP BY score.user_id
ORDER BY score.score DESC, score.id DESC
The output is not ordered by the latest score.id, but it does show only unique user_id's:
id user_id score
1 1 90
3 2 55
4 3 30
7 4 30
It should be like:
id user_id score
6 3 100
2 1 70
3 2 55
7 4 30
I hope you can help me
You could use:
with cte as (
select id,
user_id,
score,
row_number() over(partition by user_id order by id desc) as row_num
from score
) select cte.id,user_id,score
from cte
inner join members m on cte.user_id=m.id
where row_num=1
order by score desc;
Demo
If your MySQL server doesn't support windows function, use:
select s.id,s.user_id,s.score
from score s
inner join members m on s.user_id=m.id
where s.id in (select max(id) as id
from score
group by user_id
)
order by score desc;
Demo

How can I get the sum of a row using LIMIT

id
reg_No
Subj_id
sub_title
score
Class_id
1
98
23
MATHEMATICS
90
2
2
98
21
ENGLISH LANG
60
2
3
98
24
PHYSICS
78
2
4
98
23
CHEMISTRY
100
2
5
98
21
BIOLOGY
81
2
6
98
24
AGRICULTURE
87
2
I want to select the best SUM(score) of the four(4) subjects including English and mathematics.
It suppose to sum 90+60+100+87 = 337
But, it's summing the entire column
Here is my query
SELECT SUM(score)
FROM table1
WHERE reg_no = 98
AND class_id=2
ORDER BY CASE WHEN sub_title IN ('English Language','Mathematics')
THEN 0
ELSE 1 END, score DESC LIMIT 4
The priority of SELECT is higher than LIMIT, therefore, you have to use a subquery
SELECT sum(score)
FROM
(
SELECT *
FROM tab
WHERE reg_no = 98 AND class_id=2
ORDER BY CASE WHEN sub_title IN ('English Language','Mathematics')
THEN 0
ELSE 1 END, score DESC
LIMIT 4
) t
DEMO
An easy way to split into two queries. The first one gets the Math and English score values, and the second one gets the two highest scores from the remaining values.
SQL Server:
With CTE As (
Select Top 2 Score From table1 Where reg_no = 98 And class_id=2 And sub_title Not In ('MATHEMATICS','ENGLISH LANG')
Order by Score Desc
Union All
Select Score From table1 Where reg_no = 98 And class_id=2 And sub_title In ('MATHEMATICS','ENGLISH LANG')
)
Select Sum(Score)
From CTE
MySQL:
With CTE As (
Select Score
From
(Select Score From table1 Where reg_no = 98 And class_id=2 And sub_title Not In ('MATHEMATICS','ENGLISH LANG')
Order by Score Desc
Limit 2) As S
Union All
Select Score From table1 Where reg_no = 98 And class_id=2 And sub_title In ('MATHEMATICS','ENGLISH LANG')
)
Select Sum(Score)
From CTE

PHP SQL order by multiple rows

I have a table called 'scorelist' with the following results:
ID USER_ID SCORE SEASON
-----------------------------
1 1 35 3
2 1 45 2
3 2 80 3
4 2 85 1
5 3 65 2
I want to make a score list where I show the scores of the users but only of their last played season.
Result should be:
ID USER_ID SCORE SEASON
-----------------------------
3 2 80 3
5 3 65 2
1 1 35 2
I use the following code:
SELECT * FROM scorelist
WHERE season = (
SELECT season FROM scorelist ORDER BY season DESC LIMIT 1
)
GROUP BY user_id
ORDER BY score DESC;
But then I only get the results of season 3, so a lot of users are not shown.
I also tried:
SELECT * FROM scorelist group by user_id ORDER BY score DESC, season DESC
But this is also not working.
I hope you can help me.
The subquery gets the latest season for each user. If you join to that you get your desired results
SELECT s1.*
FROM scorelist s1
JOIN
(
SELECT user_id, max(season) AS season
FROM scorelist
GROUP BY user_id
) s2 ON s1.user_id = s2.user_id AND s1.season = s2.season
Since MySQL 8.0 you can use window function row_number to solve this problem:
WITH ordered_scorelist AS (
SELECT
scorelist.*,
row_number() over (partition by USER_ID order by SEASON DESC) rn
FROM scorelist
) SELECT
USER_ID, SCORE, SEASON
FROM ordered_scorelist
WHERE rn = 1
ORDER BY SCORE DESC;
MySQL row_number test

"SELECT id, title, #natusort:=#natusort + 1 AS ordercount" does not increment as expected

My query in MySQL does not behave as expected.
SET #natusort := 0;
SELECT id, title, #natusort:=#natusort + 1 AS ordercount
FROM categories
JOIN table1 ON id = table1.parentid
ORDER BY title LIMIT 10
I expected a set of results like this:
ID title ordercount
------------------------------------
67 aaa 1
23 aab 2
65 aac 3
47 aad 4
78 aba 5
32 abc 6
43 abd 7
33 aca 8
46 acb 9
12 acd 10
But I got this set instead:
ID title ordercount
------------------------------------
67 aaa 12
23 aab 3
65 aac 12
47 aad 34
78 aba 4
32 abc 36
43 abd 31
33 aca 15
46 acb 19
12 acd 50
How can I get the increment to work sequentially starting from 1 and follow the order by?
You can use ROW_NUMBER(), as in:
SELECT id, title,
row_number() over(order by title) as ordercount
FROM categories
JOIN table1 ON id = table1.parentid
ORDER BY title
LIMIT 10
What appears to be happening here is that first your sequence is being generated across the result set, and then you are limiting to 10 records based on some order. What you're left with isn't necessarily a sequence from 1 to 10. The best fix here might be to use ROW_NUMBER, if you are using MySQL 8+. If you must stick with your current approach, then wrap in a subquery before generating the sequence:
SELECT id, title, #natusort:=#natusort + 1 AS ordercount
FROM
(
SELECT id, title
FROM categories
INNER JOIN table1 ON id = table1.parentid
ORDER BY title
LIMIT 10
) t
ORDER BY title;
For the ROW_NUMBER option, just change your select to:
SELECT id, title, ROW_NUMBER() OVER (ORDER BY title) AS ordercount
FROM categories
...
You should use row_number() in MySQL 8+.
The issue you are having is that ORDER BY and GROUP BY are not compatible with variables in more recent versions of MySQL pre-8.0. I don't remember exactly when this stopped working, but I have in mind GROUP BY stopped working in 5.6 and ORDER BY in 5.7. I wish I could forget such trivia.
In any case, the solution is to order in a subquery:
SELECT tc.*, (#natusort := #natusort + 1) AS ordercount
FROM (SELECT id, title
FROM categories c JOIN
table1 t1
ON c.id = t1.parentid
ORDER BY title
) tc CROSS JOIN
(SELECT #natusort := 0) params
ORDER BY title
LIMIT 10;
Note that I've included the initialization of #natusort in the same query, so only one statement is necessary.
If using SET #natusort := 0at the beginning is not working then you can Initialize it using joins example :
SELECT id, title, (#natusort:=#natusort + 1) AS ordercount
FROM categories
JOIN table1 ON id = table1.parentid
inner join (SELECT #natusort := 0)
ORDER BY title LIMIT 10