Mysql
 sql >> Database >  >> RDS >> Mysql

Il resto in PostgreSQL, MS SQL Server, MySQL e SQLite

Problema:

Vuoi trovare il resto (non negativo).

Esempio:

Nella tabella numbers , hai due colonne di numeri interi:a e 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

Vuoi calcolare i resti dalla divisione di a da b . Ogni resto deve essere un valore intero non negativo inferiore a b .

Soluzione 1 (non del tutto corretta):

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

Il risultato è:

a b resto
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 errore
0 0 errore

Discussione:

Questa soluzione funziona correttamente se a non è negativo. Tuttavia, quando è negativo, non segue la definizione matematica del resto.

Concettualmente, un resto è ciò che rimane dopo una divisione intera di a da b . Matematicamente, un resto di due numeri interi è un numero intero non negativo minore del divisore b . Più precisamente, è un numero r∈{0,1,...,b - 1} per il quale esiste un numero intero k tale che a =k * b + r.

Questo è esattamente come a % b funziona per i dividendi non negativi nella colonna a :

5 = 1 * 3 + 2 , quindi il resto di 5 e 3 è uguale a 2 .

9 = 3 * 3 + 0 , quindi il resto di 9 e 3 è uguale a 0 .

5 = (-1) * (-3) + 2 , quindi il resto di 5 e -3 è uguale a 2 .

Ovviamente viene visualizzato un errore se il divisore b è 0 , perché non puoi dividere per 0 .

Ottenere il resto corretto è problematico quando il dividendo a è un numero negativo Sfortunatamente, a % b può restituire un valore negativo quando a è negativo. Es.:

-2 % 5 restituisce -2 quando dovrebbe restituire 3 .

-5 % -3 restituisce -2 quando dovrebbe restituire 1 .

Soluzione 2 (corretta per tutti i numeri):

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

Il risultato è:

a b resto
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 errore
0 0 errore

Discussione:

Per calcolare il resto di una divisione di qualsiasi due interi (negativi o non negativi), puoi usare il CASE WHEN costruzione. Se a % b non è negativo, il resto è semplicemente a % b . Altrimenti, dobbiamo correggere il risultato restituito da a % b .

Se a % b restituisce un valore negativo, dovresti aggiungere il valore assoluto di un divisore a a % b . Cioè, rendilo a % b + ABS(b) :

-2 % 5 restituisce -2 quando dovrebbe restituire 3 . Puoi risolvere il problema aggiungendo 5 .

-5 % (-3) restituisce -2 quando dovrebbe restituire 1 . Puoi risolvere il problema aggiungendo 3 .

Quando a % b restituisce un valore negativo, il CASE WHEN il risultato dovrebbe essere a % b + ABS(b) . Ecco come ottenere la Soluzione 2. Se hai bisogno di un aggiornamento su come ABS() funziona, dai un'occhiata al ricettario Come calcolare un valore assoluto in SQL.

Naturalmente, se b = 0 , continuerai a ricevere un errore.

Soluzione 3 (corretta per tutti i numeri):

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

Il risultato è:

a b resto
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 errore
0 0 errore

Discussione:

C'è un altro modo per risolvere questo problema. Invece di un CASE WHEN , usa una formula matematica di una riga più complessa:

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

Nella Soluzione 2, a % b + ABS(b) è stato restituito per i casi in cui a % b < 0 . Nota che a % b + ABS(b) = a % b + ABS(b) * 1 when a % b < 0 .

Quindi, possiamo moltiplicare ABS(b) da un'espressione uguale a 1 per valori negativi di a % b e 0 per valori non negativi di a % b . Dal momento che a % b è sempre un numero intero, l'espressione a % b + 0.5 è sempre positivo per a % b >= 0 e negativo per a % b < 0 . Puoi utilizzare qualsiasi numero positivo inferiore a 1 invece di 0.5 .

La funzione segno SIGN() restituisce 1 se il suo argomento è strettamente positivo, -1 se è strettamente negativo e 0 se è uguale a 0 . Tuttavia, hai bisogno di qualcosa che restituisca solo 0 e 1 , non 1 e -1 . Ma non preoccuparti! Ecco come risolvere questo problema:

(1 - 1) / 2 = 0

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

Quindi, l'espressione corretta per la quale devi moltiplicare ABS(b) è:

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

Quindi, l'intera formula è:

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