sql >> Databáze >  >> RDS >> Mysql

Jak získat zbytek pomocí MOD() v PostgreSQL, MS SQL Server a MySQL

Problém:

Chcete najít (nezáporný) zbytek.

Příklad:

V tabulce numbers , máte dva sloupce celých čísel:a a 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

Chcete vypočítat zbytek z dělení a od b . Každý zbytek by měl být nezáporné celé číslo menší než b .

Řešení 1 (není zcela správné):

SELECT
  a,
  b,
  MOD(a, b) AS remainder
FROM numbers;

Výsledek je:

a b zbytek
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 chyba
0 0 chyba

Diskuse:

Toto řešení funguje správně, pokud a není záporné. Když je však záporný, neřídí se matematickou definicí zbytku.

Koncepčně je zbytek to, co zůstane po celočíselném dělení a od b . Matematicky je zbytek dvou celých čísel nezáporné celé číslo, které je menší než dělitel b . Přesněji je to číslo r∈{0,1,...,b - 1} pro které existuje nějaké celé číslo k takové, že a =k * b + r . Např.:

5 = 1 * 3 + 2 , takže zbytek 5 a 3 se rovná 2 .

9 = 3 * 3 + 0 , takže zbytek 9 a 3 se rovná 0 .

5 = (-1) * (-3) + 2 , takže zbytek 5 a -3 se rovná 2 .

Takto MOD(a, b) funguje pro nezáporné dividendy ve sloupci a . Je zřejmé, že pokud je dělitel b, zobrazí se chyba je 0 , protože nemůžete dělit 0 .

Získání správného zbytku je problematické, když je dividenda a záporné číslo. Bohužel MOD(a, b) může vrátit zápornou hodnotu, když je a záporné. Např.:

MOD(-2, 5) vrátí -2 kdy by měl vrátit 3 .

MOD(-5, -3) vrátí -2 kdy by měl vrátit 1 .

Řešení 2 (správné pro všechna čísla):

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

Výsledek je:

a b zbytek
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 chyba
0 0 chyba

Diskuse:

Chcete-li vypočítat zbytek dělení mezi jakékoli dvě celá čísla (záporná nebo nezáporná), můžete použít CASE WHEN konstrukce. Když MOD(a, b) je nezáporné, zbytek je jednoduše MOD(a, b) . V opačném případě musíme opravit výsledek vrácený MOD(a, b) .

Jak získáte správný zbytek, když MOD() vrátí zápornou hodnotu? Absolutní hodnotu dělitele byste měli přidat do MOD(a, b) . To znamená, že MOD(a, b) + ABS(b) :

MOD(-2, 5) vrátí -2 kdy by měl vrátit 3 . Můžete to opravit přidáním 5 .

MOD(-5, -3) vrátí -2 kdy by měl vrátit 1 . Můžete to opravit přidáním 3 .

Když MOD(a, b) vrátí záporné číslo, CASE WHEN výsledek by měl být MOD(a, b) + ABS(b) . Takto získáváme řešení 2. Pokud si potřebujete zopakovat, jak ABS() funkce funguje, podívejte se do kuchařky Jak vypočítat absolutní hodnotu v SQL.

Samozřejmě stále nemůžete dělit žádné číslo 0 . Pokud tedy b = 0 , zobrazí se chyba.

Řešení 3 (správné pro všechna čísla):

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

Výsledek je:

a b zbytek
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 chyba
0 0 chyba

Diskuse:

Existuje jiný způsob, jak tento problém vyřešit. Místo CASE WHEN , použijte složitější jednořádkový matematický vzorec:

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

V řešení 2 MOD(a, b) + ABS(b) byl vrácen pro případy, kdy MOD(a, b) < 0 . Všimněte si, že MOD(a, b) + ABS(b) = MOD(a, b) + ABS(b) * 1 when MOD(a, b) < 0 .

Naproti tomu vrátíte MOD(a, b) když MOD(a, b) >= 0 . Všimněte si, že MOD(a, b) = MOD(a, b) + ABS(b) * 0 when MOD(a, b) >= 0 .

Můžeme tedy vynásobit ABS(b) výrazem, který se rovná 1 pro záporné MOD(a, b) a 0 pro nezáporný MOD(a, b) . Od MOD(a, b) je vždy celé číslo, výraz MOD(a, b) + 0.5 je vždy kladné pro MOD(a, b) ≥ 0 a záporné pro MOD(a, b) < 0 . Můžete použít jakékoli kladné číslo menší než 1 místo 0.5 .

Funkce znaku SIGN() vrátí 1 pokud je jeho argument striktně kladný, -1 pokud je přísně záporné, a 0 pokud se rovná 0 . Potřebujete však něco, co vrátí pouze 0 a 1 , nikoli 1 a -1 . Zde je návod, jak to opravit:

(1 - 1) / 2 = 0

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

Potom správný výraz, kterým vynásobíte ABS(b) je:

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

Takže celý vzorec je:

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


  1. SQLite Select Distinct

  2. Agregáty a dělení

  3. Jak zkrátit tabulku s omezením cizího klíče?

  4. Připojení k MySQL pomocí Pythonu