计算每个ID的连续重复值的长度

时间:2019-10-06 09:02:19

标签: sql sql-server tsql presto

我有一个表格,如屏幕截图所示(前两列),我需要创建一列,就像最后一列一样。我正在尝试计算每个id的连续值的每个序列的长度。

为此,最后一列是必需的。我玩过

extension AVAudioPlayerNode{

    var current: TimeInterval{
        if let nodeTime = lastRenderTime,let playerTime = playerTime(forNodeTime: nodeTime) {
            return Double(playerTime.sampleTime) / playerTime.sampleRate
        }
        return 0
    }
}

,但并没有取得太大的成功,因为圈出的数字(相当可预测)计算为2而不是1。

请帮助!

Initial table & column I need to fill

4 个答案:

答案 0 :(得分:3)

首先,我们需要一种方法来定义行的排序方式。例如,在示例数据中,无法确保始终在“第二”行(1, 1)之前显示“第一”行(1,0)

这就是为什么在示例数据中添加了一个Identity列的原因。在实际情况下,详细信息可以按行ID,日期列或其他方式排序,但是您需要确保可以通过唯一条件对行进行排序。

因此,任务非常简单:

  1. 计算触发开关-更改值时
  2. 计算组
  3. 计算行

就是这样。为了方便您理解逻辑,我使用了通用表表达式并保留了所有列。您可以在单独的语句中随意更改它,并删除一些列。

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];

enter image description here

答案 1 :(得分:2)

您想要的结果取决于数据源中 actual 数据的顺序。在SQL中,您对关系进行操作,有时对关系行进行排序。除非您在源表中引入用于对数据进行排序的其他列(例如,自动递增或某个时间戳列),否则在SQL方面,您所需的最终结果不是很明确。

注意:这回答了原始问题,并且未考虑注释中提到的“额外时间戳”列。我没有更新我的答案,因为已经有一个可以接受的答案。

答案 2 :(得分:1)

一种解决方法是通过递归CTE:

There is no option, use [^] or [\s\S] / [\d\D] / [\w\W] instead of a dot. 

这将返回以下内容:

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)

在此处查看我的小演示:https://rextester.com/ZZEIU93657

CTE起作用的先决条件是有序列表(例如其中有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 列的表)作为源。在我的示例中,我为此介绍了列identity。首先,我需要找到源表的第一个条目。就我而言,这是带有i的条目。

对于更长的源表,您可能会遇到递归限制错误,因为i=1的默认值为100。在这种情况下,您应该取消上面MAXRECURSION子句后面的OPTION设置的注释。您可以将其设置为更高的值(如图所示),也可以通过将其设置为0完全关闭它。

答案 3 :(得分:0)

恕我直言,使用游标和循环更容易做到这一点。

也许有一种方法可以通过自连接完成工作

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