在 CTE 中创建块 - SQL Server
Posted
技术标签:
【中文标题】在 CTE 中创建块 - SQL Server【英文标题】:Creating blocks within a CTE - SQL Server 【发布时间】:2013-12-04 06:41:26 【问题描述】:我正在尝试解决如何标记唯一(我所称的)块(或段,如果你愿意的话),这些块具有基于开始和结束的连续“Trip”行,由“epoch”排序,共享相同的“代码” '。在这种情况下,按“行程”分组,“代码”将不起作用,因为我需要测量“代码”的持续时间在行程中保持不变。我曾尝试使用 CTE,但我无法对数据进行分区,以提供如下所示的所需结果。我显示的区块编号可以是任何值,只要它是唯一的,以便它按照“时代”的顺序标记旅行中相同“代码”的连续出现。
有什么想法吗?
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
【问题讨论】:
什么版本的sql server? 另外,为什么输出中的最后一行 (trip=2, code=1, epoch=31631629) 不是第四行...与其他 trip=2, code=1记录? trip=1, code=1 行的相同问题。 SQL 2008 R2 并感谢我在深夜打卡时收到的随机数据。当我一天后回到这个问题时,我也注意到了这一点。无论如何,我已经取得了一些进展,这将有所帮助。 这是一个“缝隙和孤岛”问题,我已经添加了相应的标签。 谢谢'Andriy M',我完全不知道这个词。这将有助于缩小范围。 【参考方案1】:你没有更新你的预期输出,所以我仍然不能 100% 确定这是你想要的,但试一试......
SELECT
DENSE_RANK() OVER (ORDER BY trip, code),
*
FROM
@data
ORDER BY
trip, code, epoch
【讨论】:
感谢您的帮助,我想需要进一步澄清一下。最终目标是测量行程代码开始和行程代码更改代码/行程结束时的时代差异。将“代码”想象成一个警报级别,其中业务 KPI 可能是为了确保相同的警报不会持续 30 秒,但行程可能稍后会继续并发出警报,但它被视为新案例KPI 衡量。【参考方案2】:好的,无论如何它都远非完美,但它是一个启动器,至少可以识别连续块的开始和结束,其中“代码”在旅途中保持不变。为了至少贡献一些东西,我会发布我急于求成的东西。如果我有时间做一份合适的工作,我会发布它。
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
【讨论】:
以上是关于在 CTE 中创建块 - SQL Server的主要内容,如果未能解决你的问题,请参考以下文章
在 SQL Server 中结合 CTE“WITH”和“WITH XMLNAMESPACES....”