achieve "order by" before "group by" in mysql - mysql

i have a DB with this structure
id, UserID, price, Date
,1, 10.00, 2000-01-01
,1, 25.00 ,2022-02-01
,2, 12.00 ,2000-01-05
,2, 13.00 ,2001-01-05
,2, 24.00 ,2022-01-01
,3, 23.00 ,2022-01-01
i want to show the price for each user based on newest date.
So just 1 row per UserID (latest date)
if we query above table. results need to be like this:
,1, 25.00 ,2022-02-01
,2, 24.00 ,2022-01-01
,3, 23.00 ,2022-01-01
i have tried those 2 commands but they are not working
SELECT UserID,price,Datee FROM (SELECT UserID,price,Datee FROM tbl
ORDER BY UserID ASC,datee DESC) as tb_temp GROUP BY UserID
also this
SELECT UserID,price,max(Datee) FROM tbl Group by UserID ORDER BY UserID ASC,datee DESC
this command show latest date but price is not based on that
so i need something like ORDER BY datee then group by userID or LIMIT 1 per userID

If you're on MySQL 8, the most common way to achieve this is with a window function:
select userid, price, date
from (select *
, row_number() over (partition by userid
order by date desc) as row_priority
from tbl
) subq
where subq.row_priority = 1
Here's a working demo on dbfiddle

You could use a window function to good effect as MarcinJ has done--another approach would be to use a correlated subquery:
SELECT
S1.UserID,
S1.price,
S1.Date
FROM
SampleDetails S1
WHERE
S1.Date = (SELECT MAX(S2.Date) FROM SampleDetails S2 WHERE S2.UserID = S1.UserID GROUP BY S2.UserID);
You can try it out on DB Fiddle.

You could try this, it's not the most efficient because it uses a sub-query:
SELECT t.UserID, t.price, t.Datee
FROM tbl t
JOIN tbl on t.id = (SELECT id FROM tbl WHERE UserID = t.UserID ORDER BY Datee DESC LIMIT 1)
GROUP BY UserID
The idea is to join the table to itself by finding the latest row for the user id.
I made this sql fiddle to test it: http://sqlfiddle.com/#!9/63d495/2

Related

I want to calculate the sum of last transaction for A&B

Let's say the table looks like this:
user id
date
Amount
123
2022/11/01
5
456
2022/11/02
6
789
2022/11/03
8
123
2022/11/02
9
456
2022/11/04
6
789
2022/11/05
8
I want to calculate the sum of the very last transaction (only one for each user) for A & B FYI I'm using redash and I'm a beginner not sure what other info would you need, I tried MAX but was not sure how to apply it on more than one specific user.
Get the sum of Amount where user is A or B and date is the most recent date for each user
SELECT SUM(AMOUNT) AS total
FROM (
SELECT AMOUNT, ROW_NUMBER() OVER (PARTITION BY USERID ORDER BY DATE DESC) AS RN
FROM tableyoudidnotname
WHERE userid in ('A','B')
) X
WHERE X.RN = 1
You can try this, where we first calculate the maximum date by user in a common-table expression, then join that result-set to the table to sum the associated values.
WITH dat
AS
(
SELECT user_id, MAX(date) AS max_date
FROM credit.card
WHERE user_id IN ('A','B','ETC')
GROUP BY user_id
)
SELECT SUM(value) AS sum_on_max_dates
FROM credit.card t
INNER JOIN dat d ON t.user_id = d.user_id AND t.date = m.max_date;
You can try this, Used join with the subquery I mention below.
SELECT
SUM(t1.amount) AS count
FROM
transaction t1
JOIN
(SELECT
user_id, MAX(date) AS max_date
FROM
transaction
WHERE
user_id IN ('A', 'B')
GROUP BY user_id) t2 ON t1.user_id = t2.user_id
AND t2.max_date = t1.date;

MySQL - Group and return single row for each group based on most recent

So I'm having an issue with what I expect is a very simple problem, but for the life of me I can't figure it out!
I have a table like this:
id name status date
1 bob good 01/01/2020
2 john good 01/01/2020
3 bob bad 02/01/2020
4 john good 02/01/2020
5 ben good 02/01/2020
I want to retrieve the latest record for each name.
I have tried the following:
SELECT name
,STATUS
,MAX(DATE)
FROM TABLE
GROUP BY name
ORDER BY MAX(DATE)
I thought this worked, however it is returning a record for bob, john and ben, but it is showing bobs date as 02/01/2020 but his status as "good" from the other record!
At a loss as to how to do this in the simplest way possible, all help is much appreciated!
Don't think of this as aggregation. Think of this as filtering!
Select t.name, t.status, t.date
from table t
where t.date = (select max(t2.date)
from table t2
where t2.name = t.name
);
You are not aggregating anything. Your result set just wants columns from one row, the row with the maximum date for each name. That is more like filtering than grouping.
With not exists:
select t.* from tablename t
where not exists (
select 1 from tablename
where name = t.name and date > t.date
)
The result is:
every row of the table for which there is not another row with the same name and later date.
For MySql 8.0+ you can use ROW_NUMBER() window function:
select t.id, t.name, t.status, t.date
from (
select *, row_number() over (partition by name order by date desc) rn
from tablename
) t
where t.rn = 1
Maria DB 10.2 apparently. – Ed Jones
SELECT DISTINCT name,
FIRST_VALUE(status) OVER (PARTITION BY name
ORDER BY date DESC) status,
MAX(date) OVER (PARTITION BY name) date
FROM table;
The index by (name, data) will increase the performance.

MYSQL: How to get Maximum and Second Maximum Date in single query

I am trying to select Maximum Date and Second Max Date but can't get success.
This is table data.
ID Country DATE
1 Canada 2016-05-26
2 Canada 2016-05-25
3 Canada 2016-05-24
4 USA 2016-04-02
5 USA 2016-04-01
6 USA 2016-03-20
Expecting Output
Country Max_Date 2nd_Date
Canada 2016-05-26 2016-05-25
USA 2016-04-02 2016-04-01
What I have done so for:
Get Max Date using this query.
select Country, MAX(Date) from tbl GROUP BY (Country);
For Second Max date but failed to get result:
SELECT Country, MAX(date) FROM tbl WHERE Date NOT IN
( select MAX(FROM) from tbl GROUP BY (Country)) GROUP BY (Country)
What should I try to get expected output. Thanks
Or you could try this
SELECT s.Country, Max(s.Date) Max_Date,
(SELECT t.Date
FROM tbl t
Where s.Country=t.Country
ORDER BY Date DESC
LIMIT 1,1) 2nd_Date
FROM tbl s
GROUP BY COUNTRY;
The LIMIT clause is zero based, so using parameters 1,1 skips the first (ie max) value & returns just one value (2nd max).
NOTE - if the max date is duplicated the query will return Max_Date & 2nd_Date as the same value - if that is not what you want, then you can add DISTINCT to the inner query.
No need for nested queries to solve this:
SELECT t1.country, max(t1.date), max(t2.date)
FROM tbl t1
JOIN tbl t2 ON t1.country = t2.country AND t2.date < t1.date
GROUP BY t1.country;
This can be a pain. Here is one method:
select t.country, maxdate, max(t.date) as secondate
from tbl t left join
(select country, max(date) as maxdate
from tbl
group by country
) c
on t.country = c.country and t.date < c.maxdate
group by t.country;
Try this one
Select Country, MAX(Date) As Date From tbl GROUP BY Country Order By Date Desc Limit 2;

MYSQL DISTINCT and ORDER BY together

I have a table like the following
item_id position_number position_date
1 9 2013-06-29 15:12:58
2 7 2013-07-25 15:12:58
18 5 2013-07-08 12:07:00
13 9 2013-07-08 12:07:00
I want to get the items group by position_number and order by position_date DESC, so the query will return the following:
item_id position_number position_date
13 9 2013-07-08 12:07:00
2 7 2013-07-25 15:12:58
18 5 2013-07-08 12:07:00
I've been implementing some of the solutions that use DISTINCT and GROUP BY, but not get the desired result.
Does anyone have an idea about how to solved it?
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT position_number, MAX(position_date) position_date
FROM tableName
GROUP BY position_number
) b ON a.position_number = b.position_number AND
a.position_date = b.position_date
ORDER BY a.position_number DESC
SQLFiddle Demo
Given your example data, this query will return the specified resultset:
SELECT t.item_id
, t.position_number
, t.position_date
FROM ( SELECT MAX(n.item_id) AS max_item_id
FROM mytable n
GROUP BY position_number
) m
JOIN mytable t
ON t.item_id = m.max_item_id
ORDER BY t.position_number DESC
NOTE This is choosing a single item_id for each position_number. This is assuming that a given item_id will appear only once, and have a single position_number. (If an item_id can be associated with multiple postion_number, the query can be tweaked. This is using the MAX() function to choose the item_id with the largest value. (The only example of a row being excluded is item_id=1.)
try this
select * from your_table group by position_number order by position_date DESC
EDIT:
SELECT `item_id`, max(`position_number`) position_number , max(`position_date`) position_date FROM TABLENAME
GROUP BY POSITION_NUMBER
ORDER BY POSITION_DATE DESC
DEMO
Here is SQLFiddle
SELECT * FROM TABLE_NAME
GROUP BY POSITION_NUMBER
ORDER BY POSITION_DATE DESC
Try this code:
SELECT * FROM TABLE_NAME GROUP BY POSITION_NUMBER ORDER BY POSITION_DATE DESC
Use GROUP_BY and either MIN or MAX to decide which date in the group you want to use for sorting.
SELECT * FROM my_table GROUP BY position_number ORDER BY MAX(position_date) DESC;

Retrieve the second latest record with same id

From the following four records, I want to select the OwnerId of second-latest record
ItemId OwnerId Date
11477 20981 2013-05-13
11477 1 2013-05-21
11477 21086 2013-05-22 #this is the one I'm talking about
11477 3868 2013-05-24
How to go about it?
This needs ItemID to be specified,
SELECT *
FROM TableName
WHERE ItemID = '11477'
ORDER BY DATE DESC
LIMIT 1,1
SQLFiddle Demo
However, if you don't want to specify the ItemID, and you want to get all second latest record for every ItemID, you can use a correlated subquery to generate a sequence number for every ItemID based on lastest DATE,
SELECT ItemId, OwnerID, Date
FROM
(
SELECT A.ItemId,
A.OwnerId,
A.Date,
(
SELECT COUNT(*)
FROM tableName c
WHERE c.ItemId = a.ItemId AND
c.Date >= a.Date) AS RowNumber
FROM TableName a
) x
WHERE RowNumber = 2
SQLFiddle Demo
select ownerid
from your_table
order by date desc
limit 1, 1
I think you can just to ORDER BY date descending, which will give you an order from newer to older, then LIMIT 1,1 to get only the second result, which should be the one you look for
SELECT *
FROM table
ORDER BY date DESC
LIMIT 1,1