Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

La différence entre chaque valeur de ligne - Erreur de somme

Ce dont vous avez essentiellement besoin, c'est de prétendre temporairement que c2.reading n'a pas bouclé après avoir atteint 1 000 000, et cela uniquement lorsque c2.reading < c1.reading . Autrement dit, à ce stade, vous devrez augmenter c2.reading par 1 000 000, puis soustrayez c1.reading . Et quand c2.reading >= c1.reading , la requête doit calculer la différence "normale", c'est-à-dire soustraire c1.reading à partir de l'original (non augmenté) c2.reading valeur.

Une façon d'atteindre cette logique serait de faire quelque chose d'aussi simple que ceci :

SUM(
  CASE WHEN c2.reading < c1.reading THEN 1000000 ELSE 0 END
  + c2.reading
  - ISNULL(c1.reading, c2.reading)
) AS Count1

Cependant, il existe également une approche différente.

Vos valeurs de lecture et, par conséquent, les différences entre deux d'entre elles ne peuvent jamais dépasser 1 000 000. Par conséquent, vous pouvez librement appliquer modulo 1 000 000 à une différence positive et cela vous rendra la même différence :

d mod 1,000,000 = d

De plus, ajouter des multiples de 1 000 000 à une différence positive n'affectera pas le résultat du modulo 1 000 000 car, selon la distributivité de l'opération modulo,

  (d + 1,000,000 * n) mod 1,000,000 =
= d mod 1,000,000 + (1,000,000 * n) mod 1,000,000

La première somme, d mod 1,000,000 résultats en d , le second, (1,000,000 * n) mod 1,000,000 donne 0, d + 0 = d .

D'un autre côté, ajouter 1 000 000 à un négatif différence nous donnerait une différence positive correcte.

Donc, pour résumer,

  • ajouter 1 000 000 à une différence négative nous donne une différence positive (correcte),

  • une différence positive modulo 1 000 000 donne la même différence positive, et

  • l'ajout de 1 000 000 à une différence positive n'affecte pas le résultat du modulo 1 000 000.

Compte tenu de tout cela, nous pouvons nous retrouver avec l'expression universelle suivante pour calculer une seule différence :

(1000000 + c2.reading - ISNULL(c1.reading, c2.reading)) % 1000000

% est l'opérateur modulo dans Transact- SQL .

Mettez l'expression dans SUM pour obtenir les valeurs agrégées correspondantes :

SUM((c2.reading + 1000000 - ISNULL(c1.reading, c2.reading)) % 1000000) AS Count1