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
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:
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 )
This question already has answers here:
Rank function in MySQL
(13 answers)
Closed 2 years ago.
Having a table like this
+--------+------------+
| orderID | productID |
+--------+------------+
| 100 | 10 |
| 100 | 11 |
| 101 | 10 |
| 101 | 11 |
| 101 | 12 |
+--------+------------+
I need to add a third column, which be counter of current position of product.
Like:
+--------+------------+--------------+
| orderID | productID | currentIndex |
+--------+------------+--------------+
| 100 | 10 | 1 |
| 100 | 11 | 2 |
| 101 | 10 | 1 |
| 101 | 11 | 2 |
| 101 | 12 | 3 |
+--------+------------+--------------+
Can help me, please?
I have now this query:
SELECT orderID, productID
FROM orders;
If you are running MySQL 8.0, `row_number() does exactly what you ask for:
select orderid, productid,
row_number() over(partition by orderid order by productid) currentindex
from orders;
In earlier versions, alternatives are either user variables, or a correlated subquery. I am going to recommend the second option - user variables are rather tricky to work with, and are now officially planned for future deprecation:
select orderid, productid,
(select count(*) from orders o1 where o1.orderid = o.orderid and o1.productid <= o.productid) currentindex
from orders o;
How do I sort a table by it's minimum value per group but at the same time keep a group of rows together. Below a simple example of what i am trying to accomplish. The table is sorted by the lowest group value, but the group remains together. I am pretty sure this question has been asked already but i could not find an answer.
+---------+-------+
| Group | value |
+---------+-------+
| 1 | 3.99 |
| 1 | 10.99 |
| 3 | 12.69 |
| 1 | 20.95 |
| 2 | 19.95 |
| 3 | 10.09 |
+---------+-------+
Desired output
+---------+-------+
| Group | value |
+---------+-------+
| 1 | 3.99 |
| 1 | 10.99 |
| 1 | 20.95 |
| 3 | 10.69 |
| 3 | 12.09 |
| 2 | 19.95 |
+---------+-------+
If you are running MySQL 8.0, you can sort with window functions:
select t.*
from mytable t
order by min(value) over(partition by grp), value
In earlier versions, one option is to join an aggregate subquery:
select t.*
from mytable t
inner join (
select grp, min(value) min_value from mytable group by grp
) m on m.grp = t.grp
order by m.min_value, t.value
SELECT *,RN = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY VALUE,ID) FROM TEMP
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