通过聚合将表连接到自身

时间:2016-12-05 16:44:09

标签: sql sql-server tsql self-join

我正在尝试(有效地)从连接表中获取行,其中startdate是cpid中的最新行 - 对于选定的cpid来说。

这是一个连接表中数据的示例,其中我想要标记为<<<<

的行
select cpid, max(startdate)
from connections
where cpid in (  
20,
30,
40
)
group by cpid

此查询返回最新的startdate和cpid,但我不确定如何将其与自身连接以获得我需要的结果:

connid   cpid  startdate
3        20    9/12/16
5        30    8/23/16
8        40    5/18/16

我正在寻找的结果如下:

local[*]

任何帮助将不胜感激! ROBM

2 个答案:

答案 0 :(得分:5)

这样的事情:

WITH Numbered AS
(
    SELECT ROW_NUMBER() OVER(PARTITION BY cpid ORDER BY startdate DESC) AS Nr
          ,*
    FROM connections
)
SELECT *
FROM Numbered
WHERE Nr=1;

函数ROW_NUMBER()将为行添加一个运行编号。 PARTITION BY允许您重新启动组的运行编号,ORDER BY允许您定义编号的顺序。使用DESC,您将获得最新信息,因此Nr = 1。

更新:老式......

如果你需要在除SQL-Server之外的其他系统上使用它,你可能会采用老式的方式:

SET DATEFORMAT mdy;
DECLARE @tbl TABLE(connid INT,  cpid INT,  startdate DATE);
INSERT INTO @tbl VALUES
( 1,20,'7/17/16')
,(2,20,'8/23/16')
,(3,20,'9/12/16')
,(4,30,'6/17/16')
,(5,30,'8/23/16')
,(6,40,'2/24/16')
,(7,40,'3/17/16')
,(8,40,'5/18/16') ;

SELECT * 
FROM @tbl AS tbl
WHERE tbl.startdate IN(SELECT MAX(x.startdate) FROM @tbl AS x WHERE x.cpid=tbl.cpid)

答案 1 :(得分:1)

这是使用CROSS APPLY而不是CTE的替代解决方案,执行计划是不同的,一旦您在您的环境中尝试它,它可能会更有效。

DROP TABLE #connections
CREATE TABLE #connections(connid INT, cpid INT,startdate datetime)

INSERT INTO  #connections(connid,cpid,startdate)
VALUES
(1,'20','20160717')
,(2,'20','20160823')
,(3,'20','20160912')
,(4,'30','20160617')
,(5,'30','20160823')
,(6,'40','20160224')
,(7,'40','20160317')
,(8,'40','20160518')

SELECT 
    c.connid,c.cpid,c.startdate
FROM
#connections c
CROSS APPLY (
    SELECT
        cpid
        ,MAX(startdate) startdate
    FROM
        #connections
    GROUP BY
        cpid
    ) a
WHERE
    c.cpid = a.cpid
    AND c.startdate = a.startdate