sql >> Database >  >> RDS >> Mysql

De rest in PostgreSQL, MS SQL Server, MySQL en SQLite

Probleem:

U wilt de (niet-negatieve) rest vinden.

Voorbeeld:

In de tabel numbers , je hebt twee kolommen met gehele getallen:a en b .

een b
9 3
5 3
2 3
0 3
-2 3
-5 3
-9 3
5 -3
-5 -3
5 0
0 0

U wilt de resten berekenen van het delen van a door b . Elke rest moet een niet-negatief geheel getal zijn dat kleiner is dan b .

Oplossing 1 (niet helemaal correct):

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

Het resultaat is:

een 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 fout
0 0 fout

Discussie:

Deze oplossing werkt correct als a niet-negatief is. Als het echter negatief is, volgt het niet de wiskundige definitie van de rest.

Conceptueel is een rest wat overblijft na een geheeltallige deling van a door b . Wiskundig gezien is een rest van twee gehele getallen een niet-negatief geheel getal dat kleiner is dan de deler b . Om precies te zijn, het is een getal r∈{0,1,...,b - 1} waarvoor een geheel getal k bestaat zodat a =k * b + r.

Dit is precies hoe a % b werkt voor de niet-negatieve dividenden in de kolom a :

5 = 1 * 3 + 2 , dus de rest van 5 en 3 is gelijk aan 2 .

9 = 3 * 3 + 0 , dus de rest van 9 en 3 is gelijk aan 0 .

5 = (-1) * (-3) + 2 , dus de rest van 5 en -3 is gelijk aan 2 .

Uiteraard wordt er een fout getoond als de deler b is 0 , omdat je niet kunt delen door 0 .

Het verkrijgen van de juiste rest is problematisch wanneer het deeltal a is een negatief getal. Helaas, a % b kan een negatieve waarde retourneren wanneer a is negatief. Bijv.:

-2 % 5 retourneert -2 wanneer het 3 moet retourneren .

-5 % -3 retourneert -2 wanneer het 1 moet teruggeven .

Oplossing 2 (correct voor alle getallen):

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

Het resultaat is:

een 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 fout
0 0 fout

Discussie:

Om de rest van een deling van elke . te berekenen twee gehele getallen (negatief of niet-negatief), kunt u de CASE WHEN gebruiken bouw. Als a % b is niet-negatief, de rest is gewoon a % b . Anders moeten we het resultaat corrigeren dat wordt geretourneerd door a % b .

Als a % b een negatieve waarde retourneert, moet u de absolute waarde van een deler toevoegen aan a % b . Dat wil zeggen, maak het a % b + ABS(b) :

-2 % 5 retourneert -2 wanneer het 3 moet retourneren . U kunt dit oplossen door 5 . toe te voegen .

-5 % (-3) retourneert -2 wanneer het 1 moet teruggeven . U kunt dit oplossen door 3 . toe te voegen .

Wanneer a % b geeft een negatieve waarde terug, de CASE WHEN resultaat moet a % b + ABS(b) . zijn . Dit is hoe u oplossing 2 krijgt. Als u een opfriscursus nodig heeft over hoe de ABS() functie werkt, bekijk het kookboek Hoe bereken je een absolute waarde in SQL.

Natuurlijk, als b = 0 , krijg je nog steeds een foutmelding.

Oplossing 3 (correct voor alle getallen):

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

Het resultaat is:

een 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 fout
0 0 fout

Discussie:

Er is een andere manier om dit probleem op te lossen. In plaats van een CASE WHEN , gebruik een complexere wiskundige formule van één regel:

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

In Oplossing 2, a % b + ABS(b) werd geretourneerd voor gevallen waarin a % b < 0 . Merk op dat a % b + ABS(b) = a % b + ABS(b) * 1 when a % b < 0 .

We kunnen dus ABS(b) . vermenigvuldigen door een uitdrukking die gelijk is aan 1 voor negatieve waarden van a % b en 0 voor niet-negatieve waarden van a % b . Sinds a % b is altijd een geheel getal, de uitdrukking a % b + 0.5 is altijd positief voor a % b >= 0 en negatief voor a % b < 0 . U kunt elk positief getal kleiner dan 1 . gebruiken in plaats van 0.5 .

De tekenfunctie SIGN() retourneert 1 als het argument strikt positief is, -1 als het strikt negatief is, en 0 als het gelijk is aan 0 . U hebt echter iets nodig dat alleen 0 . teruggeeft en 1 , niet 1 en -1 . Maar geen zorgen! Zo los je dit op:

(1 - 1) / 2 = 0

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

Vervolgens de juiste uitdrukking waarmee u ABS(b) . moet vermenigvuldigen is:

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

De hele formule is dus:

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


  1. Onderhoud van SQL Server-systeemdatabases

  2. Problemen oplossen bij het werken met datum en tijd in SQL Server

  3. Meerdere MySQL-instanties op dezelfde machine uitvoeren

  4. Wat ik graag zou willen zien in Amazon EC2 voor databasebeheer