This question already has answers here:
How can I SELECT rows with MAX(Column value), PARTITION by another column in MYSQL?
(22 answers)
Closed 2 years ago.
So I have this table and I am trying to get the latest analysis_id
+----+---------+-------------+
| id | repo_id | analysis_id |
+----+---------+-------------+
| 1 | 20 | 3 |
+----+---------+-------------+
| 2 | 20 | 4 |
+----+---------+-------------+
| 3 | 20 | 5 |
+----+---------+-------------+
| 4 | 21 | 6 |
+----+---------+-------------+
| 5 | 22 | 7 |
+----+---------+-------------+
So how do I get the largest number from analysis_id without the repeating repo_id
+----+---------+-------------+
| id | repo_id | analysis_id |
+----+---------+-------------+
| 3 | 20 | 5 |
+----+---------+-------------+
| 4 | 21 | 6 |
+----+---------+-------------+
| 5 | 22 | 7 |
+----+---------+-------------+
A general MySQL 8+ friendly solution uses ROW_NUMBER:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY repo_id ORDER BY analysis_id DESC) rn
FROM yourTable
)
SELECT id, repo_id, analysis_id
FROM cte
WHERE rn = 1;
You are looking for group by
SELECT MAX(id) ,repo_id ,MAX(analysis_id)
FROM YOUR_TABLE
GROUP BY repo_id
In MySQL 5+ you may use
SELECT *
FROM tablename t1
WHERE NOT EXISTS ( SELECT NULL
FROM tablename t2
WHERE t1.repo_id = t2.repo_id
AND t1.id < t2.id )
Related
This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 1 year ago.
Please assume this table:
// mytable
+--------+-------------+---------+
| num | business_id | user_id |
+--------+-------------+---------+
| 3 | 503 | 12 |
| 7 | 33 | 12 |
| 1 | 771 | 13 |
| 2 | 86 | 13 |
| 1 | 772 | 13 |
| 4 | 652 | 14 |
| 4 | 567 | 14 |
+--------+-------------+---------+
I need to group it based on user_id, So, here is my query:
select max(num), user_id from mytable
group by user_id
Here is the result:
// res
+--------+---------+
| num | user_id |
+--------+---------+
| 7 | 12 |
| 2 | 13 |
| 4 | 14 |
+--------+---------+
Now I need to also get the business_id of those rows. Here is the expected result:
// mytable
+--------+-------------+---------+
| num | business_id | user_id |
+--------+-------------+---------+
| 7 | 33 | 12 |
| 2 | 86 | 13 |
| 4 | 567 | 14 | -- This is selected randomly, because of the equality of values
+--------+-------------+---------+
Any idea how can I do that?
You don't group. You filter. One method uses window functions such as row_number():
select t.*
from (select t.*,
row_number() over (partition by user_id order by num desc) as seqnum
from mytable t
) t
where seqnum = 1;
Another method which can have slightly better performance with an index on (user_id, num) is a correlated subquery:
select t.*
from mytable t
where t.num = (select max(t2.num)
from mytable t2
where t2.user_id = t.user_id
);
You should think "group by" when you want to summarize rows. You should think "where" when you want to choose rows with particular characteristics.
This question already has answers here:
Grouping by a Top N in MySQL
(2 answers)
Closed 2 years ago.
I have a table to list the transaction made by users.
mysql> select * from transaction;
+-----------+----------+------------+
| emp_id_fk | trans_id | trans_date |
+-----------+----------+------------+
| 1 | 1 | 2008-01-01 |
| 1 | 2 | 2019-01-01 |
| 1 | 3 | 2020-01-01 |
| 2 | 4 | 2020-01-10 |
| 2 | 5 | 2020-01-16 |
| 2 | 6 | 2020-01-15 |
+-----------+----------+------------+
6 rows in set (0.00 sec)
I want to know the last 2 transactions made by the users along with their transaction ID.
The output should look something like this.
+-----------+----------+------------+
| emp_id_fk | trans_id | trans_date |
+-----------+----------+------------+
| 1 | 2 | 2019-01-01 |
| 1 | 3 | 2020-01-01 |
| 2 | 5 | 2020-01-16 |
| 2 | 6 | 2020-01-15 |
+-----------+----------+------------+
I've tried inner joins and group by clause but of no use. How can I generate this output?
If you are running MySQL 8.0, you can use window fuctions:
select *
from (
select t.*, row_number() over(partition by emp_id_fk order by trans_date desc) rn
from transactions t
) t
where rn <= 2
order by emp_id_fk, trans_date
If there may be more than one transaction for a given customer on the same date, consider adding another sorting criteria to the order by clause of the window function, such as trans_id for example:
row_number() over(partition by emp_id_fk order by trans_date desc, , trans_id) rn desc
In older versions, you could use a correlated subquery:
select t.*
from transactionts t
where (
select count(*)
from transactions t1
where t1.trans_date >= t.trans_date and t1.emp_id_fk = t.emp_id_fk
) <= 2
Given we have following table where the series number and the the date should increment
+----+--------+------------+
| id | series | date |
+----+--------+------------+
| 1 | 10 | 2020-08-13 |
| 2 | 9 | 2020-08-02 |
| 3 | 8 | 2020-06-23 |
| 4 | 7 | 2020-06-08 |
| 5 | 6 | 2020-05-20 |
| 6 | 5 | 2020-05-05 |
| 7 | 4 | 2020-05-01 |
+----+--------+------------+
Is there a way to check if there are records that do not follow this pattern ?
For example row 2 has bigger series number but it's date is before row 3
+----+--------+------------+
| id | series | date |
+----+--------+------------+
| 1 | 10 | 2020-08-13 |
| 2 | 9 | 2020-06-02 |
| 3 | 8 | 2020-07-23 |
| 4 | 7 | 2020-06-08 |
| 5 | 6 | 2020-05-20 |
| 6 | 5 | 2020-05-05 |
| 7 | 4 | 2020-05-01 |
+----+--------+------------+
You can use window functions:
select *
from (
select t.*, lead(date) over(order by series) lead_date
from mytable t
) t
where date > lead_date
Alternatively:
select *
from (
select t.*, lead(series) over(order by date) lead_series
from mytable t
) t
where series > lead_series
You can use lag():
select t.*
from (select t.*,
lag(id) over (order by series) as prev_id_series,
lag(id) over (order by date) as prev_id_date
from t
) t
where prev_id_series <> prev_id_date;
You can fetch problematic rows and their corresponding conflicting rows using SELF JOIN like this (assuming your table is called "series"):
SELECT s1.id AS row_id, s1.series AS row_series, s1.date AS row_date,
s2.id AS conflict_id, s2.series AS conflict_series, s2.date AS conflict_date
FROM series AS s1
JOIN series AS s2
ON s1.series > s2.series AND s1.date < s2.date;
This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 5 years ago.
I have a table called Stats in my database:
| Game_ID | User_ID | Rank | Creation_date |
---------------------------------------------
| 1 | 1 | 1 | 2017-04-03 |
| 1 | 2 | 2 | 2017-04-03 |
| 1 | 3 | 3 | 2017-04-03 |
| 1 | 1 | 4 | 2017-05-03 |
And I currently use the following query to fetch all rows for a specific Game_ID:
"SELECT * FROM Stats WHERE Game_ID = 2 ORDER BY Rank ASC"
This returns exactly what is shown above, I would however like to return only one row per User_ID (The one with the most recent Creation_date), like this:
| Game_ID | User_ID | Rank | Creation_date |
---------------------------------------------
| 1 | 2 | 2 | 2017-04-03 |
| 1 | 3 | 3 | 2017-04-03 |
| 1 | 1 | 4 | 2017-05-03 |
Any help would be appreciated!
EDIT
I tried the solution above, and I'm certain it is the right one. I dont get duplicates anymore of the User_ID. However, I don't get the latest Creation_date. What am I missing?
The updated query:
SELECT a.Game_ID, a.User_ID, a.rank, a.Creation_date
FROM stats a
INNER JOIN (
SELECT User_ID, MAX(Creation_date), Creation_date
FROM stats
WHERE Game_ID = 2
GROUP BY User_ID
) b ON a.User_ID = b.User_ID AND a.Creation_date = b.Creation_date ORDER BY rank ASC;
Returns:
| Game_ID | User_ID | Rank | Creation_date |
---------------------------------------------
| 1 | 1 | 1 | 2017-04-03 |
| 1 | 2 | 2 | 2017-04-03 |
| 1 | 3 | 3 | 2017-04-03 |
In other words, not the row with the most recent Creation_date for User_ID 1.
Try this -
SELECT Game_ID, User_ID, MAX(Rank), Max(Creation_date)
FROM Stats
WHERE Game_ID = 2
GROUP BY Game_ID, User_ID, Creation_date
ORDER BY Rank, Creation_date
I am working on the project and one of the things that I need to do, is to select some data
table:
id | unit_id | data1 | data2 | data 3 | data4 | TimeStamp
1 | 1 | 1 | 1 | 1 | 2012-10-18 18:17:42
2 | 1 | 2 | 2 | 2 | 2012-10-18 18:18:42
3 | 1 | 3 | 5 | 3 | 2012-10-20 18:19:42
4 | 1 | 4 | 7 | 4 | 2012-10-21 18:20:42
5 | 1 | 5 | 8 | 8 | 2012-10-22 18:21:42
6 | 2 | 1 | 1 | 1 | 2012-10-18 18:17:42
7 | 2 | 2 | 2 | 4 | 2012-10-19 18:18:42
8 | 2 | 3 | 2 | 5 | 2012-10-20 18:19:42
9 | 2 | 4 | 3 | 6 | 2012-10-21 18:20:42
and what I need, is to get Single LATEST value for EACH unit_id
The following query will group the records by unit_id and identifies the one with latest timestamp, joins those results with the same table and selects the record with the unit_id and timestamp values.
SELECT
a.*
FROM
MyTable a
JOIN (SELECT
unit_id,
MAX(TimeStamp) 'TimeStamp'
FROM
MyTable
GROUP BY unit_id
) as b
ON a.unit_id = b.unit_id AND a.Timestamp = b.TimeStamp
By using GROUP BY clause, like
SELECT
unit_id, max(TimeStamp)
FROM
table3
GROUP BY
unit_id
Try this
SELECT unit_id , max(tstamp)
FROM t
GROUP BY unit_id
SELECT max(timestamp),unit_id FROM table GROUP BY unit_id