Reputation: 2711
My table looks something like this:
group date cash checks
1 1/1/2013 0 0
2 1/1/2013 0 800
1 1/3/2013 0 700
3 1/1/2013 0 600
1 1/2/2013 0 400
3 1/5/2013 0 200
-- Do not need cash just demonstrating that table has more information in it
I want to get the each unique group where date is max and checks is greater than 0. So the return would look something like:
group date checks
2 1/1/2013 800
1 1/3/2013 700
3 1/5/2013 200
attempted code:
SELECT group,MAX(date),checks
FROM table
WHERE checks>0
GROUP BY group
ORDER BY group DESC
problem with that though is it gives me all the dates and checks rather than just the max date row.
using ms sql server 2005
Upvotes: 92
Views: 636877
Reputation: 1
SELECT *
INTO #temp
FROM
(
VALUES
(1, '1/1/2013', 0, 0),
(2, '1/1/2013', 0, 800),
(1, '1/3/2013', 0, 700),
(3, '1/1/2013', 0, 600),
(1, '1/2/2013', 0, 400),
(3, '1/5/2013', 0, 200)
) x ([group], date, cash, checks);
-- Method 1
SELECT distinctgroup.[group],
max_date.date,
max_date.cash,
max_date.checks
FROM
(SELECT DISTINCT [group] FROM #temp) distinctgroup
CROSS APPLY
(
SELECT TOP 1
[group],
date,
cash,
checks
FROM #temp t
WHERE distinctgroup.[group] = t.[group]
ORDER BY date DESC
) max_date;
-- Method2
SELECT ot.[group],
ot.date,
ot.cash,
ot.checks
FROM
(SELECT it.[group],
it.date,
it.cash,
it.checks, ROW_NUMBER() OVER (PARTITION BY [group] ORDER BY date DESC) AS rownum
FROM #temp it) ot
WHERE ot.rownum=1
DROP TABLE #temp;
Upvotes: 0
Reputation: 3248
Using an in
can have a performance impact. Joining two subqueries will not have the same performance impact and can be accomplished like this:
SELECT *
FROM (SELECT msisdn
,callid
,Change_color
,play_file_name
,date_played
FROM insert_log
WHERE play_file_name NOT IN('Prompt1','Conclusion_Prompt_1','silent')
ORDER BY callid ASC) t1
JOIN (SELECT MAX(date_played) AS date_played
FROM insert_log GROUP BY callid) t2
ON t1.date_played = t2.date_played
Upvotes: 5
Reputation: 59
SELECT distinct
group,
max_date = MAX(date) OVER (PARTITION BY group), checks
FROM table
Should work.
Upvotes: 5
Reputation: 7180
SELECT group,MAX(date) as max_date
FROM table
WHERE checks>0
GROUP BY group
That works to get the max date..join it back to your data to get the other columns:
Select group,max_date,checks
from table t
inner join
(SELECT group,MAX(date) as max_date
FROM table
WHERE checks>0
GROUP BY group)a
on a.group = t.group and a.max_date = date
Inner join functions as the filter to get the max record only.
FYI, your column names are horrid, don't use reserved words for columns (group, date, table).
Upvotes: 186
Reputation: 77677
You can use a window MAX() like this:
SELECT
*,
max_date = MAX(date) OVER (PARTITION BY group)
FROM table
to get max dates per group
alongside other data:
group date cash checks max_date
----- -------- ---- ------ --------
1 1/1/2013 0 0 1/3/2013
2 1/1/2013 0 800 1/1/2013
1 1/3/2013 0 700 1/3/2013
3 1/1/2013 0 600 1/5/2013
1 1/2/2013 0 400 1/3/2013
3 1/5/2013 0 200 1/5/2013
Using the above output as a derived table, you can then get only rows where date
matches max_date
:
SELECT
group,
date,
checks
FROM (
SELECT
*,
max_date = MAX(date) OVER (PARTITION BY group)
FROM table
) AS s
WHERE date = max_date
;
to get the desired result.
Basically, this is similar to @Twelfth's suggestion but avoids a join and may thus be more efficient.
You can try the method at SQL Fiddle.
Upvotes: 56