DomG
DomG

Reputation: 61

T-SQL OVER/PARTITION BY query with condition

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

Answers (6)

e_i_pi
e_i_pi

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

krokodilko
krokodilko

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

Yogesh Sharma
Yogesh Sharma

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

DancingFool
DancingFool

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

Jayasurya Satheesh
Jayasurya Satheesh

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

Fahmi
Fahmi

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

Related Questions