代码之家  ›  专栏  ›  技术社区  ›  Kaii

SQL中连续行的分组依据

  •  4
  • Kaii  · 技术社区  · 15 年前

    给出下表:

    ID   State  Date
    12   1      2009-07-16 10:00
    45   2      2009-07-16 13:00
    67   2      2009-07-16 14:40
    77   1      2009-07-16 15:00
    89   1      2009-07-16 15:30
    99   1      2009-07-16 16:00
    

    问题:
    如何按字段“状态”分组,同时仍保持状态更改之间的边界?

    SELECT MIN(ID) AS ID, State, MIN(Date) AS Date, COUNT(ID) AS Count
    FROM table GROUP BY State
    

    结果如下:

    ID   State  Date              Count
    12   1      2009-07-16 10:00  4
    45   2      2009-07-16 13:00  2
    


    但这是意料之中的:

    ID   State  Date              Count
    12   1      2009-07-16 10:00  1
    45   2      2009-07-16 13:00  2
    77   1      2009-07-16 15:00  3
    


    这在SQL中是可能的吗?到目前为止我还没有找到解决办法…

    4 回复  |  直到 10 年前
        1
  •  9
  •   Quassnoi    15 年前
    SELECT  MIN(id) AS id, MIN(ts) AS ts, MIN(state) AS state, COUNT(*) cnt
    FROM    (
            SELECT  @r := @r + (@state != state) AS gn,
                    @state := state AS sn,
                    s.*
            FROM    (
                    SELECT  @r := 0,
                            @state := 0
                    ) vars,
                    t_state s
            ORDER BY
                    ts
            ) q
    GROUP BY
            gn
    

    用于测试的表创建脚本:

    CREATE TABLE t_state (id INT NOT NULL PRIMARY KEY, state INT NOT NULL, ts DATETIME NOT NULL);
    
    INSERT
    INTO  t_state
    VALUES
    (12,   1,      '2009-07-16 10:00'),
    (45,   2,      '2009-07-16 13:00'),
    (67,   2,      '2009-07-16 14:40'),
    (77,   1,      '2009-07-16 15:00'),
    (89,   1,      '2009-07-16 15:30'),
    (99,   1,      '2009-07-16 16:00');
    
        2
  •  2
  •   wqw    15 年前

    这是如何使用MSSQL服务器上的CTE执行此操作。

    -- DROP TABLE MyLog
    CREATE TABLE MyLog(
            ID          INT PRIMARY KEY
            , State     INT
            , Date      DATETIME
            )
    INSERT MyLog
    SELECT 12, 1, '2009-07-16 10:00' UNION ALL
    SELECT 45, 2, '2009-07-16 13:00' UNION ALL
    SELECT 67, 2, '2009-07-16 14:40' UNION ALL
    SELECT 77, 1, '2009-07-16 15:00' UNION ALL
    SELECT 89, 1, '2009-07-16 15:30' UNION ALL
    SELECT 99, 1, '2009-07-16 16:00'
    
    ;WITH   CTE
    AS      (
            SELECT  ROW_NUMBER() OVER(ORDER BY ID) AS RowNo
                    , *
            FROM    MyLog
            )
    , MyLogGroup
    AS      (
            SELECT  l.*
                    , ( SELECT  MAX(ID)
                        FROM    CTE c
                        WHERE   NOT EXISTS (SELECT * FROM CTE
                                            WHERE RowNo = c.RowNo-1 AND State = c.State)
                                AND c.ID <= l.ID) AS GroupID
            FROM    MyLog l
            )
    SELECT  *
    FROM    MyLogGroup
    
        3
  •  1
  •   gcbenison    13 年前

    Here 是对Quassnoi提供的解决方案如何工作的更详细描述

        4
  •  0
  •   bernhof    10 年前

    我可能在这里说明了明显的问题,但是如果您愿意使用Transact-SQL,您可以遍历表中的行并构建自己的结果集,这可能看起来很麻烦,但肯定会奏效。迭代可以完成 without the use of cursors .