Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Pozostałe w PostgreSQL, MS SQL Server, MySQL i SQLite

Problem:

Chcesz znaleźć (nieujemną) resztę.

Przykład:

W tabeli numbers , masz dwie kolumny liczb całkowitych:a i 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

Chcesz obliczyć reszty z dzielenia a przez b . Każda reszta powinna być nieujemną liczbą całkowitą mniejszą niż b .

Rozwiązanie 1 (nie do końca poprawne):

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

Wynik:

a b pozostałe
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 błąd
0 0 błąd

Dyskusja:

To rozwiązanie działa poprawnie, jeśli a jest nieujemne. Jednak gdy jest ujemny, nie jest zgodny z matematyczną definicją reszty.

Koncepcyjnie reszta jest tym, co pozostaje po dzieleniu całkowitym a przez b . Matematycznie reszta dwóch liczb całkowitych jest nieujemną liczbą całkowitą, która jest mniejsza niż dzielnik b . Dokładniej jest to liczba r∈{0,1,...,b - 1}, dla której istnieje pewna liczba całkowita k taka, że ​​a =k * b + r.

Dokładnie tak a % b działa dla nieujemnych dywidend w kolumnie a :

5 = 1 * 3 + 2 , więc reszta z 5 i 3 równa się 2 .

9 = 3 * 3 + 0 , więc reszta z 9 i 3 równa się 0 .

5 = (-1) * (-3) + 2 , więc reszta z 5 i -3 równa się 2 .

Oczywiście błąd jest wyświetlany, jeśli dzielnik b to 0 , ponieważ nie można dzielić przez 0 .

Uzyskanie prawidłowej reszty jest problematyczne, gdy dywidenda a jest liczbą ujemną. Niestety, a % b może zwrócić wartość ujemną, gdy a jest ujemny. Np.:

-2 % 5 zwraca -2 kiedy powinien zwrócić 3 .

-5 % -3 zwraca -2 kiedy powinien zwrócić 1 .

Rozwiązanie 2 (poprawne dla wszystkich liczb):

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

Wynik:

a b pozostałe
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 błąd
0 0 błąd

Dyskusja:

Aby obliczyć resztę z dzielenia dowolnego dwie liczby całkowite (ujemna lub nieujemna), możesz użyć CASE WHEN budowa. Jeśli a % b jest nieujemna, reszta to po prostu a % b . W przeciwnym razie musimy poprawić wynik zwrócony przez a % b .

Jeśli a % b zwraca wartość ujemną, należy dodać wartość bezwzględną dzielnika do a % b . To znaczy, zrób to a % b + ABS(b) :

-2 % 5 zwraca -2 kiedy powinien zwrócić 3 . Możesz to naprawić, dodając 5 .

-5 % (-3) zwraca -2 kiedy powinien zwrócić 1 . Możesz to naprawić, dodając 3 .

Kiedy a % b zwraca wartość ujemną, CASE WHEN wynik powinien być a % b + ABS(b) . W ten sposób otrzymujesz Rozwiązanie 2. Jeśli potrzebujesz odświeżenia na temat sposobu ABS() funkcja działa, spójrz na książkę kucharską Jak obliczyć wartość bezwzględną w SQL.

Oczywiście, jeśli b = 0 , nadal będzie się pojawiać błąd.

Rozwiązanie 3 (poprawne dla wszystkich liczb):

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

Wynik:

a b pozostałe
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 błąd
0 0 błąd

Dyskusja:

Jest inny sposób rozwiązania tego problemu. Zamiast CASE WHEN , użyj bardziej złożonego jednowierszowego wzoru matematycznego:

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

W rozwiązaniu 2 a % b + ABS(b) został zwrócony dla przypadków, gdy a % b < 0 . Zauważ, że a % b + ABS(b) = a % b + ABS(b) * 1 when a % b < 0 .

Możemy więc pomnożyć ABS(b) przez wyrażenie równe 1 dla ujemnych wartości a % b i 0 dla nieujemnych wartości a % b . Od a % b jest zawsze liczbą całkowitą, wyrażenie a % b + 0.5 jest zawsze dodatnia dla a % b >= 0 i ujemny dla a % b < 0 . Możesz użyć dowolnej liczby dodatniej mniejszej niż 1 zamiast 0.5 .

Funkcja znaku SIGN() zwraca 1 jeśli jego argument jest ściśle dodatni, -1 jeśli jest ściśle ujemna, a 0 jeśli równa się 0 . Jednak potrzebujesz czegoś, co zwraca tylko 0 i 1 , a nie 1 i -1 . Ale bez obaw! Oto jak to naprawić:

(1 - 1) / 2 = 0

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

Następnie poprawne wyrażenie, przez które należy pomnożyć ABS(b) jest:

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

Tak więc cała formuła to:

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak podłączyć mysql workbench do uruchamiania mysql w dockerze?

  2. Jak działa funkcja LEFT() w MySQL

  3. MySQL InnoDB Cluster 8.0 — kompletny przewodnik po wdrożeniu:część pierwsza

  4. Wyzwalacz ognia MySQL zarówno dla wstawiania, jak i aktualizacji

  5. Maksymalna długość MySQL i GROUP_CONCAT()