Това, от което се нуждаете, е временно да се преструвате, че c2.reading
не се уви след достигане на 1 000 000 и това само когато c2.reading < c1.reading
. Тоест в този момент ще трябва да увеличите c2.reading
с 1 000 000, след което извадете c1.reading
. И когато c2.reading >= c1.reading
, заявката трябва да изчисли "нормалната" разлика, т.е. да извади c1.reading
от оригиналния (неувеличен) c2.reading
стойност.
Един от начините да постигнете тази логика е да направите нещо толкова просто като това:
SUM(
CASE WHEN c2.reading < c1.reading THEN 1000000 ELSE 0 END
+ c2.reading
- ISNULL(c1.reading, c2.reading)
) AS Count1
Съществува обаче и различен подход.
Вашите стойности на четене и, като следствие, разликите между всеки две от тях, никога не могат да надхвърлят 1 000 000. Следователно можете свободно да прилагате modulo 1 000 000 към положителна разлика и това ще ви върне същата разлика:
d mod 1,000,000 = d
Освен това добавянето на кратни на 1 000 000 към положителна разлика няма да повлияе на резултата от модул 1 000 000, тъй като според разпределимостта на операцията модул,
(d + 1,000,000 * n) mod 1,000,000 =
= d mod 1,000,000 + (1,000,000 * n) mod 1,000,000
Първото събираемо, d mod 1,000,000
води до d
, вторият, (1,000,000 * n) mod 1,000,000
дава 0, d + 0 = d
.
От друга страна, добавяне на 1 000 000 към отрицателно разлика ще ни даде правилна положителна разлика.
И така, за да обобщим,
-
добавянето на 1 000 000 към отрицателна разлика ни дава (правилна) положителна разлика,
-
положителна разлика по модул 1 000 000 дава същата положителна разлика и
-
добавянето на 1 000 000 към положителна разлика не влияе на резултата от модул 1 000 000.
Като вземем всичко това предвид, можем да завършим със следния универсален израз за изчисляване на една разлика:
(1000000 + c2.reading - ISNULL(c1.reading, c2.reading)) % 1000000
където %
е модулният оператор в Transact- SQL
.
Поставете израза в SUM
за да получите съответните обобщени стойности:
SUM((c2.reading + 1000000 - ISNULL(c1.reading, c2.reading)) % 1000000) AS Count1