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

Jak uzyskać resztę za pomocą MOD() w PostgreSQL, MS SQL Server i MySQL?

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,
  MOD(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 . Np.:

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 .

W ten sposób MOD(a, b) działa dla nieujemnych dywidend w kolumnie a . 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 dzielna a jest liczbą ujemną. Niestety, MOD(a, b) może zwrócić wartość ujemną, gdy a jest ujemne. Np.:

MOD(-2, 5) zwraca -2 kiedy powinien zwrócić 3 .

MOD(-5, -3) zwraca -2 kiedy powinien zwrócić 1 .

Rozwiązanie 2 (poprawne dla wszystkich liczb):

SELECT
  a,
  b,
  CASE WHEN MOD(a, b) >= 0
    THEN MOD(a, b)
  ELSE
    MOD(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ć pozostałą część dzielenia między dowolnym dwie liczby całkowite (ujemna lub nieujemna), możesz użyć CASE WHEN budowa. Kiedy MOD(a, b) jest nieujemna, reszta to po prostu MOD(a, b) . W przeciwnym razie musimy poprawić wynik zwrócony przez MOD(a, b) .

Jak uzyskać poprawną resztę, gdy MOD() zwraca wartość ujemną? Powinieneś dodać wartość bezwzględną dzielnika do MOD(a, b) . Oznacza to, że zrób to MOD(a, b) + ABS(b) :

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

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

Kiedy MOD(a, b) zwraca liczbę ujemną, CASE WHEN wynik powinien mieć postać MOD(a, b) + ABS(b) . W ten sposób otrzymujemy 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 nadal nie możesz dzielić żadnej liczby przez 0 . Tak więc, jeśli b = 0 , pojawi się błąd.

Rozwiązanie 3 (poprawne dla wszystkich liczb):

SELECT
  a,
  b,
  MOD(a, b) + ABS(b) * (1 - SIGN(MOD(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:

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

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

Natomiast zwracasz MOD(a, b) gdy MOD(a, b) >= 0 . Zauważ, że MOD(a, b) = MOD(a, b) + ABS(b) * 0 when MOD(a, b) >= 0 .

Możemy więc pomnożyć ABS(b) przez wyrażenie równe 1 dla ujemnego MOD(a, b) i 0 dla nieujemnego MOD(a, b) . Od MOD(a, b) jest zawsze liczbą całkowitą, wyrażenie MOD(a, b) + 0.5 jest zawsze dodatnia dla MOD(a, b) ≥ 0 i negatywne dla MOD(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 . Oto jak to naprawić:

(1 - 1) / 2 = 0

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

Następnie poprawne wyrażenie, przez które mnożysz ABS(b) jest:

(1 - SIGN(MOD(a, b) + 0.5)) / 2

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

MOD(a, b) + ABS(b) * (1 - SIGN(MOD(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 całkowicie usunąć MySQL z Ubuntu?

  2. Wskazówki dotyczące aktualizacji klastra Percona XtraDB do wersji 8.0

  3. Połączenie nie powiodło się:Odmowa dostępu dla użytkownika 'root'@'localhost' (przy użyciu hasła:TAK) z funkcji php

  4. Jak generować zagnieżdżone obiekty json przy użyciu natywnych funkcji json mysql?

  5. Jak wykonać polecenie MySQL ze skryptu powłoki?