如果我正确理解了这个问题,ID 为 1005 的行的结果应该是 2 而不是 3,因为最大值(即 2)连续出现在 2,3 位置,然后又出现在 7,8 位置, 9 - 但该行的endValue 为 8,因此不应计算较大的连续数。
基于这种理解(这可能是不正确的,因此我写了这个问题的评论),这可以通过基于集合的方法(意思是,没有任何循环)在一些不错的 SQL 技巧的帮助下完成.
所以您要做的第一件事是使用cross apply 和table 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 来获取原始表每行中连续最大值的数量,前提是它们的列位置在 startValue 和 EndValue 之间。
最后要做的是获取每个 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.
但是,如果我最初的假设是错误的,并且 startvalue 和 endvalue 仅与搜索最大值的范围相关,(这将为您提供预期的结果)已在问题中发布),您将需要另一个 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.