在 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

在 SQL Server 中结合 CTE“WITH”和“WITH XMLNAMESPACES....”

SQL Server 公用表表达式(CTE)实现递归

SQL Server 公用表表达式(CTE)实现递归

sql server 中的 CTE (With table as) 在 hive 中等效吗?

sql server中的cte