Zasadniczo potrzebujesz tymczasowo udawać, że c2.reading
nie zawijał się po osiągnięciu 1 000 000 i to tylko wtedy, gdy c2.reading < c1.reading
. Oznacza to, że w tym momencie musisz zwiększyć c2.reading
o 1 000 000, a następnie odejmij c1.reading
. A kiedy c2.reading >= c1.reading
, zapytanie powinno obliczyć "normalną" różnicę, tj. odjąć c1.reading
z oryginalnego (nie zwiększonego) c2.reading
wartość.
Jednym ze sposobów osiągnięcia tej logiki byłoby zrobienie czegoś tak prostego jak to:
SUM(
CASE WHEN c2.reading < c1.reading THEN 1000000 ELSE 0 END
+ c2.reading
- ISNULL(c1.reading, c2.reading)
) AS Count1
Istnieje jednak również inne podejście.
Twoje wartości czytania, a w konsekwencji różnice między dowolnymi dwoma z nich, nigdy nie mogą przekroczyć 1 000 000. Dlatego możesz swobodnie zastosować modulo 1 000 000 do dodatniej różnicy, a to da ci tę samą różnicę:
d mod 1,000,000 = d
Co więcej, dodanie wielokrotności 1 000 000 do dodatniej różnicy nie wpłynie na wynik modulo 1 000 000, ponieważ zgodnie z rozkładem operacji modulo
(d + 1,000,000 * n) mod 1,000,000 =
= d mod 1,000,000 + (1,000,000 * n) mod 1,000,000
Pierwsza suma, d mod 1,000,000
wyniki w d
, drugi, (1,000,000 * n) mod 1,000,000
daje 0, d + 0 = d
.
Z drugiej strony dodanie 1 000 000 do ujemnej różnica dałaby nam prawidłową różnicę dodatnią.
Podsumowując,
-
dodanie 1 000 000 do różnicy ujemnej daje (poprawną) różnicę dodatnią,
-
dodatnia różnica modulo 1,000,000 daje tę samą dodatnią różnicę, a
-
dodanie 1 000 000 do dodatniej różnicy nie wpływa na wynik modulo 1 000 000.
Biorąc to wszystko pod uwagę, możemy otrzymać następujące uniwersalne wyrażenie do obliczenia pojedynczej różnicy:
(1000000 + c2.reading - ISNULL(c1.reading, c2.reading)) % 1000000
gdzie %
jest operatorem modulo w Transact- SQL
.
Umieść wyrażenie w SUM
aby uzyskać odpowiednie wartości zagregowane:
SUM((c2.reading + 1000000 - ISNULL(c1.reading, c2.reading)) % 1000000) AS Count1