【问题标题】:How to find max value in a row with changing如何在不断变化的情况下连续找到最大值
【发布时间】:2019-06-13 12:17:10
【问题描述】:

我有一个数据集,其中包含 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,3,3,0,0,0,1,12),
(1004,0,1,2,4,4,0,0,0,0,0,0,0,3,9),
(1005,1,2,2,1,0,0,2,2,2,1,0,0,1,8);

我期望 Id=1001 start=1,end = 7,最大值为 3 的结果,它发生了 2 次,但它们不是连续的,因此我想得到的最终输出是 1。
ID=1002 start=1, end=12, max 为 4 且只出现 1 次,所以最终输出为 1。

对于 ID = 1003,开始 = 1,结束 = 12,最大值为 3,3 出现 3 次,但其中只有 2 个是连续的,因此我希望得到 2。
对于 ID = 1004 start=3, end=9, max 为 4 它连续出现两次,因此输出应为 2。

对于 ID = 1005 start=1,end=8,max 为 2,它总共出现 5 次,连续出现 2 和 3 次,我希望得到 3 作为我的最终输出,因为它是最长的。

【问题讨论】:

  • startValueendValue 代表什么?

标签: loops tsql max apply


【解决方案1】:

如果我正确理解了这个问题,ID 为 1005 的行的结果应该是 2 而不是 3,因为最大值(即 2)连续出现在 2,3 位置,然后又出现在 7,8 位置, 9 - 但该行的endValue 为 8,因此不应计算较大的连续数。

基于这种理解(这可能是不正确的,因此我写了这个问题的评论),这可以通过基于集合的方法(意思是,没有任何循环)在一些不错的 SQL 技巧的帮助下完成.

所以您要做的第一件事是使用cross applytable value constructor 将val1...val12 列转换为行。我想这也可以使用 Pivot 来完成,但我从来没有完全掌握 pivot 的窍门,所以我更喜欢其他解决方案来获得同样的东西。
在我的代码中,这一步是在第一个公用表表达式(称为CTEValues)中完成的。

接下来,您使用a trick from Itzik Ben-Gan to handle gaps and island problems 来识别每行中的连续值组。此步骤在第二个 cte (CTEGroups) 中完成。

名为 CTEConsecutive 的第三个也是最后一个 cte 使用简单的 group by 和 count 来获取原始表每行中连续最大值的数量,前提是它们的列位置在 startValueEndValue 之间。

最后要做的是获取每个 id 的最大计数值 - 这应该会给你想要的结果。

这是完整的代码:

WITH CTEValues AS
(
    SELECT ID, startValue, EndValue, Val, ValId, IIF(Val = MAX(Val) OVER(PARTITION BY ID), 1, 0) As IsMax
    FROM #sample_data
    CROSS APPLY
    (
        SELECT *
        FROM (VALUES 
              (Val1, 1), 
              (Val2, 2), 
              (Val3, 3),
              (Val4, 4), 
              (Val5, 5), 
              (Val6, 6),
              (Val7, 7), 
              (Val8, 8), 
              (Val9, 9),
              (Val10, 10), 
              (Val11, 11), 
              (Val12, 12)
             )V(Val, ValId)
    ) vals
), CTEGroups AS
(
SELECT ID, startValue, EndValue, Val, ValId, IsMax,
        ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ValId) - 
        ROW_NUMBER() OVER(PARTITION BY ID, IsMax ORDER BY ValId) As Grp
FROM CTEValues

), CTEConsecutive AS
(
    SELECT ID, COUNT(Val) As NumOfConsecutiveMaxValues --*,  OVER(PARTITION BY Id, Grp) As NumOfValues
    FROM CTEGroups
    WHERE IsMax = 1
    AND ValId >= startValue
    AND ValId <= EndValue
    GROUP BY ID, Grp
)

SELECT ID, MAX(NumOfConsecutiveMaxValues)
FROM CTEConsecutive
GROUP BY ID
ORDER BY Id

You can see a live demo on rextester.

但是,如果我最初的假设是错误的,并且 startvalueendvalue 仅与搜索最大值的范围相关,(这将为您提供预期的结果)已在问题中发布),您将需要另一个 cte。

WITH CTEValues AS
(
    SELECT ID, startValue, EndValue, Val, ValId
    FROM #sample_data
    CROSS APPLY
    (
        SELECT *
        FROM (VALUES 
              (Val1, 1), 
              (Val2, 2), 
              (Val3, 3),
              (Val4, 4), 
              (Val5, 5), 
              (Val6, 6),
              (Val7, 7), 
              (Val8, 8), 
              (Val9, 9),
              (Val10, 10), 
              (Val11, 11), 
              (Val12, 12)
             )V(Val, ValId)
    ) vals
), CTEValuesWithMax AS
(
    SELECT ID, startValue, EndValue, Val, ValId,
            IIF(Val = (
                SELECT MAX(Val)
                FROM CTEValues AS T1
                WHERE T0.ID = T1.ID
                AND T1.ValId >= T1.startValue
                AND T1.ValId <= T1.EndValue
            ), 1, 0) As IsMax
    FROM CTEValues AS T0
)

其余代码保持不变,除了 CTEGroups 现在从 CTEValuesWithMax 中选择而不是从 CTEValues 中选择。

You can see a live demo of this as well.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-09
    • 1970-01-01
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    • 2010-11-26
    • 1970-01-01
    • 2013-12-04
    相关资源
    最近更新 更多