Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Der Rest in PostgreSQL, MS SQL Server, MySQL und SQLite

Problem:

Sie wollen den (nicht negativen) Rest finden.

Beispiel:

In der Tabelle numbers , haben Sie zwei Spalten mit ganzen Zahlen:a und b .

a b
9 3
5 3
2 3
0 3
-2 3
-5 3
-9 3
5 -3
-5 -3
5 0
0 0

Sie möchten die Reste aus der Division von a berechnen durch b . Jeder Rest sollte ein nicht negativer ganzzahliger Wert kleiner als b sein .

Lösung 1 (nicht ganz richtig):

SELECT
  a,
  b,
  a % b AS remainder
FROM numbers;

Das Ergebnis ist:

a b Rest
9 3 0
5 3 2
2 3 2
0 3 0
-2 3 -2
-5 3 -2
-9 3 0
5 -3 2
-5 -3 -2
5 0 Fehler
0 0 Fehler

Diskussion:

Diese Lösung funktioniert korrekt, wenn a nicht negativ ist. Wenn es jedoch negativ ist, folgt es nicht der mathematischen Definition des Rests.

Konzeptionell ist ein Rest das, was nach einer ganzzahligen Division von a übrig bleibt durch b . Mathematisch gesehen ist ein Rest von zwei ganzen Zahlen eine nicht negative ganze Zahl, die kleiner als der Divisor b ist . Genauer gesagt ist es eine Zahl r∈{0,1,...,b - 1}, für die es eine ganze Zahl k gibt, so dass a =k * b + r.

Genau so funktioniert a % b funktioniert für die nicht negativen Dividenden in der Spalte a :

5 = 1 * 3 + 2 , also ist der Rest von 5 und 3 gleich 2 .

9 = 3 * 3 + 0 , also ist der Rest von 9 und 3 gleich 0 .

5 = (-1) * (-3) + 2 , also ist der Rest von 5 und -3 gleich 2 .

Offensichtlich wird ein Fehler angezeigt, wenn der Divisor b ist ist 0 , da Sie nicht durch 0 teilen können .

Den korrekten Rest zu erhalten ist problematisch, wenn der Dividende a ist eine negative Zahl. Leider a % b kann einen negativen Wert zurückgeben, wenn a ist negativ. Beispiel:

-2 % 5 gibt -2 zurück wenn es 3 zurückgeben sollte .

-5 % -3 gibt -2 zurück wenn es 1 zurückgeben sollte .

Lösung 2 (richtig für alle Zahlen):

SELECT
  a,
  b,
  CASE WHEN a % b >= 0
    THEN a % b
  ELSE
    a % b + ABS(b)
  END AS remainder
FROM numbers;

Das Ergebnis ist:

a b Rest
9 3 0
5 3 2
2 3 2
0 3 0
-2 3 1
-5 3 1
-9 3 0
5 -3 2
-5 -3 1
5 0 Fehler
0 0 Fehler

Diskussion:

Um den Rest einer Division von beliebig zu berechnen zwei Ganzzahlen (negativ oder nicht negativ), können Sie den CASE WHEN verwenden Konstruktion. Wenn a % b nicht negativ ist, ist der Rest einfach a % b . Andernfalls müssen wir das von a % b zurückgegebene Ergebnis korrigieren .

Wenn a % b einen negativen Wert zurückgibt, sollten Sie den absoluten Wert eines Divisors zu a % b addieren . Das heißt, machen Sie daraus a % b + ABS(b) :

-2 % 5 gibt -2 zurück wenn es 3 zurückgeben sollte . Sie können dies beheben, indem Sie 5 hinzufügen .

-5 % (-3) gibt -2 zurück wenn es 1 zurückgeben sollte . Sie können dies beheben, indem Sie 3 hinzufügen .

Wenn a % b gibt einen negativen Wert zurück, den CASE WHEN Ergebnis sollte a % b + ABS(b) sein . So erhalten Sie Lösung 2. Wenn Sie eine Auffrischung benötigen, wie die ABS() Funktion funktioniert, werfen Sie einen Blick in das Kochbuch Wie man einen absoluten Wert in SQL berechnet.

Natürlich, wenn b = 0 , erhalten Sie weiterhin eine Fehlermeldung.

Lösung 3 (richtig für alle Zahlen):

SELECT
  a,
  b,
  a % b + ABS(b) * (1 - SIGN(a % b + 0.5)) / 2 AS remainder
FROM numbers;

Das Ergebnis ist:

a b Rest
9 3 0
5 3 2
2 3 2
0 3 0
-2 3 1
-5 3 1
-9 3 0
5 -3 2
-5 -3 1
5 0 Fehler
0 0 Fehler

Diskussion:

Es gibt eine andere Möglichkeit, dieses Problem zu lösen. Anstelle eines CASE WHEN , verwenden Sie eine komplexere einzeilige mathematische Formel:

a % b + ABS(b) * (1 - SIGN(a % b + 0.5)) / 2

In Lösung 2, a % b + ABS(b) wurde für Fälle zurückgegeben, in denen a % b < 0 . Beachten Sie, dass a % b + ABS(b) = a % b + ABS(b) * 1 when a % b < 0 .

Wir können also ABS(b) multiplizieren durch einen Ausdruck, der für negative Werte von a % b gleich 1 ist und 0 für nicht negative Werte von a % b . Seit a % b ist immer eine Ganzzahl, der Ausdruck a % b + 0.5 ist immer positiv für a % b >= 0 und negativ für a % b < 0 . Sie können jede positive Zahl kleiner als 1 verwenden statt 0.5 .

Die Zeichenfunktion SIGN() gibt 1 zurück wenn sein Argument streng positiv ist, -1 wenn es streng negativ ist, und 0 wenn es gleich 0 ist . Sie benötigen jedoch etwas, das nur 0 zurückgibt und 1 , nicht 1 und -1 . Aber keine Sorge! So beheben Sie das Problem:

(1 - 1) / 2 = 0

(1 - (-1)) / 2 = 1

Dann der richtige Ausdruck, mit dem Sie ABS(b) multiplizieren sollten ist:

(1 - SIGN(a % b + 0.5)) / 2

Die gesamte Formel lautet also:

a % b + ABS(b) * (1 - SIGN(a % b + 0.5)) / 2