Sql 计算每个id的连续重复值的长度
我有一个表,如屏幕截图前两列所示,我需要创建一个类似于最后一列的列。我试图计算每个id的每个连续值序列的长度 为此,最后一列是必需的。我和他一起玩Sql 计算每个id的连续重复值的长度,sql,sql-server,tsql,presto,Sql,Sql Server,Tsql,Presto,我有一个表,如屏幕截图前两列所示,我需要创建一个类似于最后一列的列。我试图计算每个id的每个连续值序列的长度 为此,最后一列是必需的。我和他一起玩 row_number() over (partition by id, value) 但并没有取得太大的成功,因为圆圈数字可以预测为2而不是1 请帮忙 IMHO,使用光标和循环更容易做到这一点 也许有一种方法可以通过selfjoin完成这项工作 declare @t table (id int, val int) insert into @t (i
row_number() over (partition by id, value)
但并没有取得太大的成功,因为圆圈数字可以预测为2而不是1
请帮忙
IMHO,使用光标和循环更容易做到这一点 也许有一种方法可以通过selfjoin完成这项工作
declare @t table (id int, val int)
insert into @t (id, val)
select 1 as id, 1 as val
union all select 1, 0
union all select 1, 0
union all select 1, 1
union all select 1, 1
union all select 1, 1
;with cte1 (id , val , num ) as
(
select id, val, row_number() over (ORDER BY (SELECT 1)) as num from @t
)
, cte2 (id, val, num, N) as
(
select id, val, num, 1 from cte1 where num = 1
union all
select t1.id, t1.val, t1.num,
case when t1.id=t2.id and t1.val=t2.val then t2.N + 1 else 1 end
from cte1 t1 inner join cte2 t2 on t1.num = t2.num + 1 where t1.num > 1
)
select * from cte2
您需要的结果取决于数据源中的实际数据顺序。在SQL中,您操作关系,有时操作关系行的有序集合。除非在源表中引入一个额外的列,在该列上对数据进行排序(例如,自动递增或某个时间戳列),否则您所需的最终结果在SQL方面没有很好的定义
注意:这回答了原始问题,没有考虑注释中提到的附加时间戳列。我不会更新我的答案,因为已经有一个可接受的答案。首先,我们需要有一种方法来定义行的排序方式。例如,在示例数据中,无法确保“第一”行1,1始终显示在“第二”行1,0之前 这就是为什么我在示例数据中添加了一个标识列。在实际情况中,详细信息可以按行ID、日期列或其他内容排序,但您需要确保可以通过唯一的条件对行进行排序 因此,任务非常简单: 计算触发开关-值更改时 计算组 计算行数 就这样。为了便于您理解逻辑,我使用了公共表表达式并保留了所有列。您可以在单独的语句中自由地打断它,并删除一些列
DECLARE @DataSource TABLE
(
[RowID] INT IDENTITY(1, 1)
,[ID]INT
,[value] INT
);
INSERT INTO @DataSource ([ID], [value])
VALUES (1, 1)
,(1, 0)
,(1, 0)
,(1, 1)
,(1, 1)
,(1, 1)
--
,(2, 0)
,(2, 1)
,(2, 0)
,(2, 0);
WITH DataSourceWithSwitch AS
(
SELECT *
,IIF(LAG([value]) OVER (PARTITION BY [ID] ORDER BY [RowID]) = [value], 0, 1) AS [Switch]
FROM @DataSource
), DataSourceWithGroup AS
(
SELECT *
,SUM([Switch]) OVER (PARTITION BY [ID] ORDER BY [RowID]) AS [Group]
FROM DataSourceWithSwitch
)
SELECT *
,ROW_NUMBER() OVER (PARTITION BY [ID], [Group] ORDER BY [RowID]) AS [GroupRowID]
FROM DataSourceWithGroup
ORDER BY [RowID];
解决此问题的一种方法是通过递归CTE:
create table #tmp (i int identity,id int, value int, rn int);
insert into #tmp (id,value) VALUES
(1,1),(1,0),(1,0),(1,1),(1,1),(1,1),
(2,0),(2,1),(2,0),(2,0);
WITH numbered AS (
SELECT i,id,value, 1 seq FROM #tmp WHERE i=1 UNION ALL
SELECT a.i,a.id,a.value, CASE WHEN a.id=b.id AND a.value=b.value THEN b.seq+1 ELSE 1 END
FROM #tmp a INNER JOIN numbered b ON a.i=b.i+1
)
SELECT * FROM numbered -- OPTION (MAXRECURSION 1000)
这将返回以下内容:
i id value seq
1 1 1 1
2 1 0 1
3 1 0 2
4 1 1 1
5 1 1 2
6 1 1 3
7 2 0 1
8 2 1 1
9 2 0 1
10 2 0 2
在这里查看我的小演示:
CTE工作的先决条件是顺序表e。G一种表,其中有一个标识列作为源。在我的示例中,我为此介绍了专栏I。作为起点,我需要找到源表的第一个条目。在我的例子中,这是i=1的条目
对于较长的源表,您可能会遇到递归限制错误,因为MAXRECURSION的默认值为100。在这种情况下,您应该取消注释上面我的SELECT子句后面的选项设置。您可以将其设置为更高的值,如图所示,也可以通过将其设置为0将其完全关闭。您是对的。假设存在一列时间戳,并且数据按每个id的升序排序