SQL Server:每组的第二个最大值

时间:2015-11-20 17:05:17

标签: sql-server tsql

我有一张包含以下数据的表格

CREATE TABLE Tbl
(
  ID VARCHAR(20)
  , Desc1 VARCHAR(30)
  , BALANCE_DATE DATE
);

INSERT INTO Tbl (ID, Desc1, BALANCE_DATE)
VALUES ('ID1', 'Desc 1', '10/18/2015')
  , ('ID1', 'Desc 2', '10/19/2015')
  , ('ID1', 'Desc 3', '10/22/2015')
  , ('ID1', 'Desc 4', GETDATE())
  , ('ID2', 'Desc 1', '9/18/2015')
  , ('ID2', 'Desc 2', '9/1/2015')
  , ('ID2', 'Desc 3', '9/28/2015')
  , ('ID2', 'Desc 4', GETDATE());

╔═════╦════════╦════════════════╗
║ ID  ║ Desc1  ║ BALANCE_DATE   ║
╠═════╬════════╬════════════════╣
║ ID1 ║ Desc 1 ║ 10/18/2015     ║
║ ID1 ║ Desc 2 ║ 10/19/2015     ║
║ ID1 ║ Desc 3 ║ 10/22/2015     ║
║ ID1 ║ Desc 4 ║ 11/21/2015     ║
║ ID2 ║ Desc 1 ║ 09/18/2015     ║
║ ID2 ║ Desc 2 ║ 09/01/2015     ║
║ ID2 ║ Desc 3 ║ 09/28/2015     ║
║ ID2 ║ Desc 4 ║ 11/21/2015     ║
╚═════╩════════╩════════════════╝

我需要获取当前日期以外的最新日期行。

预期产出:

╔═════╦════════╦════════════╗
║ ID1 ║ Desc 3 ║ 10/22/2015 ║
║ ID2 ║ Desc 3 ║ 9/28/2015  ║
╚═════╩════════╩════════════╝

如何查询?

2 个答案:

答案 0 :(得分:3)

WITH cteMaxDateNotCurrent AS (
    SELECT ID, MAX(BALANCE_DATE) AS MaxDate
        FROM tbl
        WHERE BALANCE_DATE <> CAST(GETDATE() AS DATE)
        GROUP BY ID
)
SELECT mdnc.ID, t.Desc1, mdnc.MaxDate
    FROM cteMaxDateNotCurrent mdnc
        INNER JOIN tbl t
            ON mdnc.ID = t.ID
                AND mdnc.MaxDate = t.BALANCE_DATE;

答案 1 :(得分:2)

虽然Joe的回答是有用的,但我强烈建议在这种情况下使用ranking functions,你不必两次加入你的桌子,这对他们来说是一个完美的用例。这将是以下查询:

SELECT * FROM prices WHERE item IN ('item1', 'item2', 'item2', 'item3');

结果:

DECLARE @Tbl TABLE
(
  ID VARCHAR(20)
  , Desc1 VARCHAR(30)
  , BALANCE_DATE DATE
);


INSERT INTO @Tbl (ID, Desc1, BALANCE_DATE)
VALUES ('ID1', 'Desc 1', '10/18/2015')
  , ('ID1', 'Desc 2', '10/19/2015')
  , ('ID1', 'Desc 3', '10/22/2015')
  , ('ID1', 'Desc 4', GETDATE())
  , ('ID2', 'Desc 1', '9/18/2015')
  , ('ID2', 'Desc 2', '9/1/2015')
  , ('ID2', 'Desc 3', '9/28/2015')
  , ('ID2', 'Desc 4', GETDATE());

;WITH CTE(ID, Desc1, BALANCE_DATE, RN)
AS (
  SELECT ID
    , Desc1
    , BALANCE_DATE
    , DENSE_RANK() OVER(PARTITION BY Id ORDER BY BALANCE_DATE DESC)
  FROM @Tbl
 )
SELECT T.ID
  , T.Desc1
  , T.BALANCE_DATE
FROM CTE AS T
WHERE T.RN = 2;

此查询应始终为每个具有第二高日期的ID选取行。

如果您想在线测试,请参阅data.stackexchange.com上的构建查询。

更新

╔═════╦════════╦═════════════════════╗
║ ID  ║ Desc1  ║    BALANCE_DATE     ║
╠═════╬════════╬═════════════════════╣
║ ID1 ║ Desc 3 ║ 2015-10-22 00:00:00 ║
║ ID2 ║ Desc 3 ║ 2015-09-28 00:00:00 ║
╚═════╩════════╩═════════════════════╝

结果:

INSERT INTO @Tbl (ID, Desc1, BALANCE_DATE)
VALUES ('ID1', 'Desc 1', '10/18/2015')
  , ('ID1', 'Desc 2', '10/19/2015')
  , ('ID1', 'Desc 3', '10/22/2015')
  , ('ID1', 'Desc 4', GETDATE())
  , ('ID2', 'Desc 1', '9/18/2015')
  , ('ID2', 'Desc 2', '9/1/2015')
  , ('ID2', 'Desc 3', '9/28/2015')
  , ('ID2', 'Desc 4', GETDATE())
  , ('ID3', 'Desc 1', '10/18/2015')
  , ('ID3', 'Desc 2', '10/15/2015');

;WITH CTE(ID, Desc1, BALANCE_DATE, RN)
AS (
  SELECT ID
    , Desc1
    , BALANCE_DATE
    , DENSE_RANK() OVER(PARTITION BY Id ORDER BY BALANCE_DATE DESC)
  FROM @Tbl
  WHERE BALANCE_DATE < CONVERT(DATE, GETDATE())
 )
SELECT T.ID
  , T.Desc1
  , T.BALANCE_DATE
FROM CTE AS T
WHERE T.RN = 1;