Если я правильно понял вопрос, результат для строки с Id 1005 должен быть 2, а не 3, потому что максимальное значение (которое равно 2) появляется последовательно в местах 2,3 и затем снова в местах 7,8, 9 - но endValue
в этом ряду равно 8, и, следовательно, большее число последовательных не должно учитываться.
Исходя из этого понимания (которое может быть неверным, отсюда и комментарий, который я написал к вопросу), это можно сделать с помощью подхода, основанного на множестве (то есть без каких-либо циклов), с помощью некоторых приятных трюков SQL .
Итак, первое, что вы хотите сделать, это использовать cross apply
с конструктором табличных значений для преобразования столбцов val1 ... val12 в строки. Я думаю, что это также можно сделать с помощью Pivot, но я так и не смог освоить Pivot, поэтому я предпочитаю другие решения, чтобы получить то же самое.
В моем коде этот шаг выполняется в первом общем табличном выражении (называемом CTEValues
).
Далее вы используете трюк Ицик Бен-Гана для обработки пробелов и проблем островов , чтобы идентифицировать группы последовательных значений в каждой строке. Этот шаг сделан во втором cte (CTEGroups
).
Третий и последний cte, называемый CTEConsecutive
, использует простую группу by и count, чтобы получить количество последовательных максимальных значений в каждой строке исходной таблицы, при условии, что их столбцы расположены между startValue
и EndValue
.
Последнее, что нужно сделать, это получить максимальное значение этого числа для каждого идентификатора - и это должно дать вам желаемые результаты.
Вот полный код:
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
Вы можете увидеть живое демо на 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
.
Вы также можете увидеть живую демонстрацию этого.