在范围内分组记录

时间:2018-07-19 10:19:31

标签: sql sql-server gaps-and-islands

我有一组具有相同值的“跟随”行,我想将它们分组在一起以形成一个从和到。提出的解决方案通常是先使用ROW_NUMBER()然后进行分组,但是我发现有些情况不起作用,通过示例可以更好地理解该情况:

WITH
CTE AS
    (SELECT *
     FROM (VALUES ('A', 37, ''),
                  ('A', 38, ''),
                  ('A', 39, ''),
                  ('A', 40, ''),
                  ('A', 41, ''),
                  ('A', 42, ''),
                  ('A', 43, ''),
                  ('B', 44, '=> error Grupo 43'),
                  ('B', 45, '=> error Grupo 43'),
                  ('C', 46, ''),
                  ('C', 47, ''),
                  ('B', 48, ''),
                  ('B', 49, ''),
                  ('B', 50, ''),
                  ('A', 51, '=> error Grupo 43'),
                  ('A', 52, '=> error Grupo 43'),
                  ('A', 53, '=> error Grupo 43')) DATA (LETRA, DESDE, ERROR) )
SELECT *,
       ROW_NUMBER() OVER (PARTITION BY LETRA ORDER BY DESDE) AS rn,
       DESDE - ROW_NUMBER() OVER (PARTITION BY LETRA ORDER BY DESDE) AS Grupo
FROM CTE
ORDER BY SINCE;

是否可以正确地对记录进行“分组”?

问候

2 个答案:

答案 0 :(得分:2)

这是一个缺口和孤岛问题,您用DESDE - ROW_NUMBER()进行的算术是正确的,但是您应该进一步按字母分组,而不只是剩下的结果。

WITH
CTE AS
    (SELECT *
     FROM (VALUES ('A', 37, ''),
                  ('A', 38, ''),
                  ('A', 39, ''),
                  ('A', 40, ''),
                  ('A', 41, ''),
                  ('A', 42, ''),
                  ('A', 43, ''),
                  ('B', 44, '=> error Grupo 43'),
                  ('B', 45, '=> error Grupo 43'),
                  ('C', 46, ''),
                  ('C', 47, ''),
                  ('B', 48, ''),
                  ('B', 49, ''),
                  ('B', 50, ''),
                  ('A', 51, '=> error Grupo 43'),
                  ('A', 52, '=> error Grupo 43'),
                  ('A', 53, '=> error Grupo 43')) DATA (LETRA, DESDE, ERROR))
,
Groups AS 
(
    SELECT
        C.*,
        GroupID = C.DESDE - ROW_NUMBER() OVER (PARTITION BY LETRA ORDER BY C.DESDE)
    FROM
        CTE AS C
)
SELECT
    C.LETRA,
    Desde = MIN(C.DESDE),
    Hasta = MAX(C.DESDE)
FROM
    Groups AS C
GROUP BY
    C.LETRA,
    C.GroupID

结果:

LETRA   Desde   Hasta
A       37      43
A       51      53
B       44      45
B       48      50
C       46      47

答案 1 :(得分:0)

如果您使用汇总,则您的代码应该可以工作:

SELECT MIN(DESDE), MAX(DESDE), ERROR
FROM (SELECT CTE.*,
             ROW_NUMBER() OVER (PARTITION BY LETRA ORDER BY DESDE) AS rn,
             DESDE - ROW_NUMBER() OVER (PARTITION BY LETRA ORDER BY DESDE) AS Grupo
      FROM CTE
     ) x
GROUP BY Grupo, ERROR;