5

给定下表:

ID 状态日期
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 状态日期计数
12 1 2009-07-16 10:00 4
45 2 2009-07-16 13:00 2

但这是所需的输出:

ID 状态日期计数
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

4 回答 4

10
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');
于 2009-07-16T10:19:24.937 回答
2

这是在 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
于 2009-07-16T10:48:25.830 回答
1

以下是关于 Quassnoi 提供的解决方案如何工作的详细描述

于 2012-01-18T22:16:55.100 回答
0

我可能会在这里说显而易见的,但如果您愿意使用 Transact-SQL,您可以遍历表的行并构建自己的结果集,这可能看起来很麻烦,但它肯定会工作. 无需使用游标即可完成迭代。

于 2009-07-16T10:21:30.533 回答