计算每个ID随参数更改而增加的系列数

时间:2019-05-31 07:42:35

标签: sql-server loops dynamic

我有一个数据集,其中包含12个不同的ID值,以及开始和结束值。我要初始化的是将起始值作为循环的开始参数,将结束值作为最后一个参数。搜索对应的谷值,并找到第一个连续的增长。

下面我发布了一个示例数据集:

create table #sample_data(
ID  VARCHAR(10), val1 INT, val2 INT, val3 INT, val4 INT, val5 INT, val6 INT, val7 INT, val8 INT, val9 INT, val10 INT, val11 INT, val12 INT, startValue INT, endValue INT  
);

insert into #sample_data values
    (1001,3,2,1,0,1,2,3,0,0,0,0,0,1,7),
    (1002,1,2,3,4,0,0,0,1,2,3,0,0,1,12),
    (1003,0,3,2,1,0,0,0,0,0,0,0,0,1,12),
    (1004,0,1,2,3,4,0,0,0,0,0,0,0,3,9),
    (1005,1,1,1,1,2,3,2,2,1,1,0,0,1,8);

这是我期望的结果: 对于ID = 1001,我的startValue为1,结束为7,算法将从val1到val7进行比较,以将每个val与下一个val进行比较,并计数一个增量直到结束。 在这种情况下,对于1001,它将为0,因为序列将从减少开始。 对于ID 1002,它也将为3(从val1到val4,当减少时它将在val5处停止) 对于ID 1003,它将为1,因为开始时仅增加 对于ID 1004,它将是2,因为它从3开始并在val9结束 对于ID 1005,它将是2,即从val4到val6的增加

我尝试通过编写CURSOR来执行此操作,但是由于我有超过300K的数据行,因此需要花费数小时来执行。如果您有更好的建议(不使用光标),我会非常感激。

2 个答案:

答案 0 :(得分:1)

您可以尝试以下方法。主要部分是每一行都转换为12行表,并带有附加的Increase列和适当的WHERE子句。

输入:

CREATE TABLE #SampleData(
   ID VARCHAR(10),
   val1 INT,
   val2 INT,
   val3 INT,
   val4 INT,
   val5 INT,
   val6 INT,
   val7 INT,
   val8 INT,
   val9 INT,
   val10 INT,
   val11 INT,
   val12 INT,
   startValue INT,
   endValue INT
);

INSERT INTO #SampleData
   (ID,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,startValue,endValue)
VALUES
   (1001,3,2,1,0,1,2,3,0,0,0,0,0,1,7),
   (1002,1,2,3,4,0,0,0,1,2,3,0,0,1,12),
   (1003,0,3,2,1,0,0,0,0,0,0,0,0,1,12),
   (1004,0,1,2,3,4,0,0,0,0,0,0,0,3,9),
   (1005,1,1,1,1,2,3,2,2,1,1,0,0,1,8),
   (1006,1,2,3,4,4,0,7,0,9,10,0,12,1,12)

T-SQL:

;WITH PreparationCTE AS (
    SELECT
       s.ID,
       v.Increase,
       ROW_NUMBER() OVER (PARTITION BY s.ID ORDER BY v.Nmr) AS Rn1,
       SUM(CASE WHEN v.Increase = -1 THEN 0 ELSE 1 END) OVER (PARTITION BY s.ID ORDER BY v.Nmr) AS Rn2
    FROM #SampleData s
    CROSS APPLY (VALUES
       (1,  Val1,  CASE WHEN Val1 < Val2   THEN 1 WHEN Val1 = Val2   THEN 0 ELSE -1 END),
       (2,  Val2,  CASE WHEN Val2 < Val3   THEN 1 WHEN Val2 = Val3   THEN 0 ELSE -1 END),
       (3,  Val3,  CASE WHEN Val3 < Val4   THEN 1 WHEN Val3 = Val4   THEN 0 ELSE -1 END),
       (4,  Val4,  CASE WHEN Val4 < Val5   THEN 1 WHEN Val4 = Val5   THEN 0 ELSE -1 END),
       (5,  Val5,  CASE WHEN Val5 < Val6   THEN 1 WHEN Val5 = Val6   THEN 0 ELSE -1 END),
       (6,  Val6,  CASE WHEN Val6 < Val7   THEN 1 WHEN Val6 = Val7   THEN 0 ELSE -1 END),
       (7,  Val7,  CASE WHEN Val7 < Val8   THEN 1 WHEN Val7 = Val8   THEN 0 ELSE -1 END),
       (8,  Val8,  CASE WHEN Val8 < Val9   THEN 1 WHEN Val8 = Val9   THEN 0 ELSE -1 END),
       (9,  Val9,  CASE WHEN Val9 < Val10  THEN 1 WHEN Val9 = Val10  THEN 0 ELSE -1 END),
       (10, Val10, CASE WHEN Val10 < Val11 THEN 1 WHEN Val10 = Val1  THEN 0 ELSE -1 END),
       (11, Val11, CASE WHEN Val11 < Val12 THEN 1 WHEN Val11 = Val2  THEN 0 ELSE -1 END),
       (12, Val12, 0)
    ) v(Nmr, Val, Increase)
    WHERE (s.startValue <= v.Nmr) AND (v.Nmr <= s.endValue)
)
SELECT ID, SUM(CASE WHEN (Increase >= 0) AND (Rn1 = Rn2) THEN Increase ELSE 0 END) AS [Count]
FROM PreparationCTE
GROUP BY ID
ORDER BY ID

输出:

----------
ID  Count
----------
1001    0
1002    3
1003    1
1004    2
1005    2
1006    3

答案 1 :(得分:0)

如果我正确理解了您的目标,则可以使用如下所示的精选案例:

select result.Id, 
    -- result.resulttext
    LEN(replace(substring(result.resulttext,1, charindex('0', result.resulttext)-1), '1', '')) as finaltesult
    from
    (select ID, 
        case when S.val1 <= S.val2   then case when S.val2  >= S.startvalue and S.val2  <= S.endvalue then case when S.val1 < S.val2 then '2' else '1' end else '1' end else '0' end +
        case when S.val2 <= S.val3   then case when S.val3  >= S.startvalue and S.val3  <= S.endvalue then case when S.val2 < S.val3 then '2' else '1' end  else '1' end else '0' end + 
        case when S.val3 <= S.val4   then case when S.val4  >= S.startvalue and S.val4  <= S.endvalue then case when S.val3 < S.val4 then '2' else '1' end  else '1' end else '0' end + 
        case when S.val4 <= S.val5   then case when S.val5  >= S.startvalue and S.val5  <= S.endvalue then case when S.val4 < S.val5 then '2' else '1' end  else '1' end else '0' end + 
        case when S.val5 <= S.val6   then case when S.val6  >= S.startvalue and S.val6  <= S.endvalue then case when S.val5 < S.val6 then '2' else '1' end  else '1' end else '0' end + 
        case when S.val6 <= S.val7   then case when S.val6  >= S.startvalue and S.val7  <= S.endvalue then case when S.val6 < S.val7 then '2' else '1' end  else '1' end else '0' end + 
        case when S.val7 <= S.val8   then case when S.val8  >= S.startvalue and S.val8  <= S.endvalue then case when S.val7 < S.val8 then '2' else '1' end  else '1' end else '0' end + 
        case when S.val8 <= S.val9   then case when S.val9  >= S.startvalue and S.val9  <= S.endvalue then case when S.val8 < S.val9 then '2' else '1' end  else '1' end else '0' end + 
        case when S.val9 <= S.val10  then case when S.val10 >= S.startvalue and S.val10 <= S.endvalue then case when S.val9 < S.val10 then '2' else '1' end  else '1' end else '0' end +
        case when S.val10 <= S.val11 then case when S.val11 >= S.startvalue and S.val11 <= S.endvalue then case when S.val10 < S.val11 then '2' else '1' end  else '1' end else '0' end +
        case when S.val11 <= S.val12 then case when S.val12 >= S.startvalue and S.val12 <= S.endvalue then case when S.val11 < S.val12 then '2' else '1' end  else '1' end else '0' end  as resulttext
    from @sample_data as S) result

这种情况会将每次转换转换为:

  • “ 0”是值valN高于valN + 1
  • 如果值与限制匹配,但valN等于valN + 1则为'1'
  • 和'2',如果从valN到vanN + 1的转换与您所有 条件

仅是处理结果字符串的问题。 如果要查看“转换后的”结果字符串,请取消注释result.resulttext。