在CTE中创建块 - SQL Server

时间:2013-12-04 06:41:27

标签: sql-server common-table-expression gaps-and-islands

我正在尝试弄清楚我如何标记唯一(我正在调用的)块(或者如果你愿意的话),这些块具有基于开始和结束的连续'Trip'行,由'epoch'命令共享相同的'代码' ”。在这种情况下,按“行程”分组,“代码”将不起作用,因为我需要测量“代码”的持续时间对于行程保持不变。我曾尝试使用CTE,但我无法以这样的方式对数据进行分区,即它给出了如下所示的结果。我显示的块编号可以是任何值,只要它是唯一的,以便它按照'epoch'的顺序标记行程中相同“代码”的连续出现。

有什么想法吗?

declare @data table (id int, trip int, code int NULL, epoch int, value1 int, value2 int);
insert into @data (id, trip, code, epoch, value1, value2)
values 
(1, 1, null, 31631613, 0, 0),
(2, 2, 1, 31631614, 10, 40),
(3, 1, 1, 31631616, 10, 60),
(4, 1, 1, 31631617, 40, 60),
(5, 2, 1, 31631617, 23, 40),
(6, 2, 2, 31631620, 27, 40),
(7, 2, 2, 31631629, 23, 40),
(9, 1, 1, 31631618, 39, 60),
(10, 1, null, 31631621, 38, 60),
(12, 1, null, 31631625, 37, 60),
(15, 1, null, 31631627, 35, 60),
(19, 1, 1, 31631630, 39, 60),
(20, 1, 1, 31631632, 40, 60),
(21, 2, 1, 31631629, 23, 40);


block   id  trip    code        epoch   value1  value2
1       1   1       NULL    31631613    0   0
2       2   2       1       31631614    10  40
2       5   2       1       31631617    23  40
3       3   1       1       31631616    10  60
3       4   1       1       31631617    40  60
3       9   1       1       31631618    39  60
4       6   2       2       31631620    27  40
4       7   2       2       31631629    23  40
5       10  1       NULL    31631621    38  60
5       12  1       NULL    31631625    37  60
5       15  1       NULL    31631627    35  60
6       19  1       1       31631630    39  60
6       20  1       1       31631632    40  60
7       21  2       1       31631629    23  40

2 个答案:

答案 0 :(得分:0)

好吧,它无论如何都不是完美的,但它至少可以确定一个连续块的起点和终点,其中'代码'对于行程保持不变。为了至少贡献一些东西,我会发布我所说的东西。如果我有时间做一份正确的工作,我会发布它。

declare @minint int; set @minint = -2147483648;
declare @maxint int; set @maxint = 2147483647;
declare @id_data table (pk int IDENTITY(1,1), id int, trip int, code int NULL, epoch int, value1 int, value2 int);

insert into @id_data VALUES(@minint, @minint, @minint, @minint, @minint, @minint);
insert into @id_data
SELECT id, trip, coalesce(code,0), epoch, value1, value2
  FROM @data
order by trip, epoch, code;
insert into @id_data VALUES(@maxint, @maxint, @maxint, @maxint, @maxint, @maxint);

WITH CTE as 
(
SELECT pk, id, trip, code, epoch, value1, value2, ROW_NUMBER() OVER (PARTITION BY trip ORDER BY epoch) as row_num
FROM @id_data
)
SELECT B.*, A.code, C.min_next_code 
FROM CTE A
INNER JOIN CTE B ON (B.pk = A.pk + 1) AND (A.code != B.code) -- SELECTS THE RECORDS     THAT START A NEW GROUP
OUTER APPLY (
SELECT min_next_code = MIN(pk) - 1 -- LOCATION OF NEXT GROUP
FROM CTE
WHERE pk > B.pk AND (trip = B.trip) AND (code != B.code)
) C
WHERE B.id < @maxint

答案 1 :(得分:0)

你没有更新你的预期输出,所以我仍然不能100%确定这是你想要的,但试一试......

SELECT 
    DENSE_RANK() OVER (ORDER BY trip, code), 
    * 
FROM 
    @data
ORDER BY 
    trip, code, epoch