Reputation: 61
I am struggling with a SQL query and while I have looked at many similar answers none of them quite fit my situation. I have a dataset as below:
Date1 Amount 1 Index Date2 Type Supplier
31/03/2018 410000.00 17 16/04/2018 06:27 102 A
31/03/2018 410000.00 17 16/04/2018 06:31 102 B
31/03/2018 400000.00 2 16/04/2018 06:37 102 A
31/03/2018 400000.00 2 16/04/2018 06:38 102 B
30/06/2018 0 20 04/07/2018 08:23 202 A
30/06/2018 0 20 04/07/2018 08:23 202 B
30/06/2018 412000.00 20 06/07/2018 12:46 102 A
30/06/2018 412000.00 20 06/07/2018 12:47 102 B
30/06/2018 442000.00 100 16/07/2018 06:27 102 A
30/06/2018 442000.00 100 16/07/2018 06:31 102 B
For each Date1 where there are multiple rows with the same Type, I only want the rows where the index matches the index of the maximum Date2 so I want this output:
Date1 Amount 1 Index Date2 Type Supplier
31/03/2018 400000.00 2 16/04/2018 06:37 102 A
31/03/2018 400000.00 2 16/04/2018 06:38 102 B
30/06/2018 0 20 04/07/2018 08:23 202 A
30/06/2018 0 20 04/07/2018 08:23 202 B
30/06/2018 442000.00 100 16/07/2018 06:27 102 A
30/06/2018 442000.00 100 16/07/2018 06:31 102 B
I feel it should be possible with some form of conditional MAX() OVER (PARTITION BY) but for the life of me I can't work out how to do it.
Upvotes: 3
Views: 9479
Reputation: 4820
I think this is what you want. Note the use of ROW_NUMBER
as opposed to RANK
- RANK
will produce multiple values of 1 where Date2
is the same, ROW_NUMBER
will produce unique incremental values for rn
:
SELECT
[Date1],
[Amount 1],
[Index],
[Date2],
[Type],
[Supplier]
FROM my_table
INNER JOIN (
SELECT
[Index],
[Type],
ROW_NUMBER() OVER (PARTITION BY [Date1], [Type] ORDER BY [Date2] DESC) AS rn
FROM my_table
) AS subquery
ON subquery.rn = 1
AND subquery.[Index] = my_table.[Index]
AND subquery.[Type] = my_table.[Type]
Upvotes: 1
Reputation: 36127
Use LAST_VALUE (Transact-SQL) analytic function together with a subquery.
The below working example is for Oracle (I prefer Oracle because I always have a problem with converting dates on SQLServer), but the idea of the query is the same, the syntax also is the same:
Demo: http://www.sqlfiddle.com/#!4/004ce7/19
SELECT * FROM (
SELECT t.* ,
last_value( "INDEX" ) OVER
( partition by date1, "TYPE" order by date2
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) xx
FROM table1 t
) x
WHERE xx = "INDEX"
ORDER BY date1;
| DATE1 | AMOUNT1 | INDEX | DATE2 | TYPE | SUPPLIER | XX |
|----------------------|---------|-------|-----------------------|------|----------|-----|
| 2018-03-31T00:00:00Z | 400000 | 2 | 2018-04-16 06:37:00.0 | 102 | A | 2 |
| 2018-03-31T00:00:00Z | 400000 | 2 | 2018-04-16 06:38:00.0 | 102 | B | 2 |
| 2018-06-30T00:00:00Z | 442000 | 100 | 2018-07-16 06:27:00.0 | 102 | A | 100 |
| 2018-06-30T00:00:00Z | 442000 | 100 | 2018-07-16 06:31:00.0 | 102 | B | 100 |
| 2018-06-30T00:00:00Z | 0 | 20 | 2018-07-04 08:23:00.0 | 202 | B | 20 |
| 2018-06-30T00:00:00Z | 0 | 20 | 2018-07-04 08:23:00.0 | 202 | A | 20 |
Upvotes: 2
Reputation: 50173
You can use correlated subquery :
select t.*
from table t
where Index = (select top (1) t1.Index
from table t1
where t1.Date1 = t.Date1 and t1.type = t.type
order by t1.date2 desc
);
Upvotes: 0
Reputation: 1267
The subquery sorts your data so that the row that controls the index is always row_no one for each grouping of date and type. The outer query returns all rows that have the same date1, type, index combo, but ignores the others
Select *
From Data D
inner join SortedData S on S.Date1 = A.Date1
and S.Type = A.Type
and S.RowNo = 1
and D.Index = A.index
(Select Date1, Type, Index, row_Number() over (Partition by Date1, Type ORDER BY Date2 DESC) as RowNo From Data) SortedData
Upvotes: 0
Reputation: 8043
try this
;WITH CTE
AS
(
SELECT
*,
MxDt =ROW_NUMBER() OVER(PARTITION BY Date1,[Type] ORDER BY Date2 DESC)
FROM YourTableName
)
SELECT
*
FROM CTE C1
WHERE EXISTS
(
SELECT
1
FROM CTE C2
WHERE [Index] = C1.[Index]
AND [Type]= C1.[Type]
AND C2.MxDt =1
)
Upvotes: 1
Reputation: 37483
Use row_number()
SELECT [Date1],[Amount 1],[Index],[Date2],[Type],[Supplier]
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY [Date1] ORDER BY [Date2] DESC) AS rn
FROM tablename
) a
WHERE a.rn in( 1,2)
Upvotes: 1