使用Lead / Lag将SQL查询中的相关记录分组

时间:2018-12-12 16:46:54

标签: sql-server sql-server-2012

给出

input_fid   near_fid
465         466
465         467
465         468
466         467
466         468
467         468
469         470
470         471

我将如何生成以下输出:

input_fid   near_fids
465         466,467,468 
469         470,471

即得到最低的fid,并且所有与它有关联的fid,避免重复。

结果集是动态的,并且定义了记录之间关系的工具的输出。因此逻辑是465接近466和467和468,466接近467到468,依此类推。但是以前没有记录接近469,因此是新的记录。

因为每次查询运行时结果集都会不同,所以我无法对查询逻辑进行硬编码。

我玩过各种领先和落后的游戏,以及使用WITH语句获得不同程度的成功,但没有什么让我觉得自己接近了。除重复项外,其他迭代非常接近的迭代是:

WITH n(input_fid, near_fid, level) AS ( SELECT input_fid, near_fid, 0 as level from results where input_fid < near_fid and input_fid between 465 and 471 and near_fid between 465 and 471 UNION ALL SELECT m.input_fid, m.near_fid, level + 1 from results where m.input_fid > m.near_fid and m.input_fid between 465 and 471 and m.near_fid between 465 and 471 and m.near_fid = n.input_fid ) SELECT input_fid, level, near_fid = STUFF((SELECT ', ' + CONVERT (VARCHAR (MAX), near_fid ) FROM n b WHERE n.input_fid = b.input_fid AND n.level = b.level order by near_fid FOR XML PATH('')), 1, 2, '') FROM n where level = 0 GROUP BY input_fid, level

1 个答案:

答案 0 :(得分:0)

这似乎是您所追求的。不确定我是否喜欢扫描表3次这一事实:

WITH VTE AS(
    SELECT *
    FROM (VALUES (465,466),
                 (465,467),
                 (465,468),
                 (466,467),
                 (466,468),
                 (467,468),
                 (469,470)) V(input_fid, near_fid))
SELECT input_fid,
       STUFF((SELECT ',' + CONVERT(varchar(3),s.near_fid)
              FROM VTE s
              WHERE s.input_fid = V.input_fid
              ORDER BY s.near_fid
              FOR XML PATH('')),1,1,'') AS near_fids
FROM VTE V
WHERE NOT EXISTS(SELECT 1
                 FROM VTE e
                 WHERE V.input_fid = e.near_fid)
GROUP BY V.input_fid;

请注意,near_fidsinput_fid的{​​{1}}的开销仅为469,因为您的示例数据不包含任何行或列,其值均为{ {1}};所以我不知道它来自哪里。