简体   繁体   中英

SQL - Join Grouped By Max Date (Including ID)

Assuming the following table...

ValueHistory ID int (identity), HistoryDate datetime, Contract_ID int, Item_ID int, Value smallmoney

I want to get out the most recent Value (based on HistoryDate) as well as the ID associated with it, grouped by Contract_ID and Item_ID.

I currently have this, which will bring out the most recent Date / Contract_ID / Item_ID, but obviously I can't group by the ID as it'll bring back too many rows. I considered using the max ID, but unfortunately because of how the date is inserted, it's possible to have a lower ID, with a more recent date.

SELECT
    MAX([HistoryDate]) as 'Max_HistoryDate',
    [Contract_ID],
    [Item_ID]
FROM [ValueHistory]
WHERE 
        [HistoryDate] < @EndDate
GROUP BY [Item_ID], [Contract_ID]

I assume there's some way of doing this with an additional subquery, but it currently escapes me.

SQL Fiddle here: http://sqlfiddle.com/#!18/655e9/1

Answer as proposed, works perfectly.

select
    ID
    , HistoryDate
    , Contract_ID
    , Item_ID
from
(
    SELECT
        HistoryDate
        , ID
        , Contract_ID
        , Item_ID
        , RowNum = ROW_NUMBER() over(partition by Contract_ID, Item_ID order by HistoryDate DESC)
    FROM ValueHistory
    WHERE HistoryDate < @EndDate
) x
where x.RowNum = 1

Pretty sure you want something like this.

select HistoryDate
    , Contract_ID
    , Item_ID
from
(
    SELECT
        HistoryDate
        , Contract_ID
        , Item_ID
        , RowNum = ROW_NUMBER() over(partition by Contract_ID order by HistoryDate DESC)
    FROM ValueHistory
    WHERE HistoryDate < @EndDate
) x
where x.RowNum = 1

I would join the result back to the original table, pairing by the Item IDs Contract IDs and the History Date matching the Max History Date.

select *
from
(select *
from [ValueHistory]
) a
join
(
SELECT
    MAX([HistoryDate]) as [Max_HistoryDate],
    [Contract_ID] as [bContract_ID],
    [Item_ID] as [bItem_ID]
FROM [ValueHistory]
WHERE 
    [HistoryDate] < @EndDate
GROUP BY [Item_ID], [Contract_ID]) b

on a.[item_id]=b.[bitem_id] and
    a.[contract_id]=b.[bcontract_id] and
    a.[HistoryDate]=b.[Max_HistoryDate]

Using cte might help:

;with cte (Max_HistoryDate,Contract_ID,Item_ID) as
(
   SELECT
      MAX([HistoryDate]) as 'Max_HistoryDate',
      [Contract_ID],
      [Item_ID]
   FROM [ValueHistory]
   WHERE [HistoryDate] < '2018-02-01'
   GROUP BY [Item_ID], [Contract_ID]
)
Select Value, ih.Contract_ID, ih.Item_ID
From ValueHistory ih
inner join cte on ih.Contract_ID = cte.Contract_ID
               and ih.Item_ID = cte.Item_ID
where ih.HistoryDate = cte.Max_HistoryDate

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM