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

Sådan får du en rest ved hjælp af MOD() i PostgreSQL, MS SQL Server og MySQL

Problem:

Du vil finde den (ikke-negative) rest.

Eksempel:

I tabellen numbers , du har to kolonner med heltal:a og 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

Du vil beregne resten ved at dividere a af b . Hver rest skal være en ikke-negativ heltalværdi, der er mindre end b .

Løsning 1 (ikke helt korrekt):

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

Resultatet er:

a b resten
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 fejl
0 0 fejl

Diskussion:

Denne løsning fungerer korrekt, hvis a er ikke-negativ. Men når den er negativ, følger den ikke den matematiske definition af resten.

Konceptuelt er en rest det, der er tilbage efter en heltalsdeling af a af b . Matematisk er en rest af to heltal et ikke-negativt heltal, der er mindre end divisoren b . Mere præcist er det et tal r∈{0,1,...,b - 1} for hvilket der findes et heltal k, således at a =k * b + r . F.eks.:

5 = 1 * 3 + 2 , så resten af ​​5 og 3 er lig med 2 .

9 = 3 * 3 + 0 , så resten af ​​9 og 3 er lig med 0 .

5 = (-1) * (-3) + 2 , så resten af ​​5 og -3 er lig med 2 .

Sådan er MOD(a, b) virker for de ikke-negative udbytter i kolonnen a . Der vises naturligvis en fejl, hvis divisoren b er 0 , fordi du ikke kan dividere med 0 .

At få den korrekte rest er problematisk, når udbyttet a er et negativt tal. Desværre, MOD(a, b) kan returnere en negativ værdi, når a er negativ. F.eks.:

MOD(-2, 5) returnerer -2 hvornår den skulle returnere 3 .

MOD(-5, -3) returnerer -2 hvornår den skulle returnere 1 .

Løsning 2 (korrekt for alle tal):

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

Resultatet er:

a b resten
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 fejl
0 0 fejl

Diskussion:

At beregne resten af ​​en division mellem enhver to heltal (negative eller ikke-negative), kan du bruge CASE WHEN konstruktion. Når MOD(a, b) er ikke-negativ, er resten blot MOD(a, b) . Ellers skal vi rette resultatet returneret af MOD(a, b) .

Hvordan får du den korrekte rest, når MOD() returnerer en negativ værdi? Du skal tilføje den absolutte værdi af divisoren til MOD(a, b) . Det vil sige, gør det til MOD(a, b) + ABS(b) :

MOD(-2, 5) returnerer -2 hvornår den skulle returnere 3 . Du kan rette dette ved at tilføje 5 .

MOD(-5, -3) returnerer -2 hvornår den skulle returnere 1 . Du kan rette dette ved at tilføje 3 .

Når MOD(a, b) returnerer et negativt tal, CASE WHEN resultatet skal være MOD(a, b) + ABS(b) . Sådan får vi løsning 2. Hvis du har brug for en genopfriskning af, hvordan ABS() funktionen virker, tag et kig i kogebogen Sådan beregnes en absolut værdi i SQL.

Selvfølgelig kan du stadig ikke dividere noget tal med 0 . Så hvis b = 0 , får du en fejl.

Løsning 3 (korrekt for alle tal):

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

Resultatet er:

a b resten
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 fejl
0 0 fejl

Diskussion:

Der er en anden måde at løse dette problem på. I stedet for en CASE WHEN , brug en mere kompleks en-linje matematisk formel:

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

I løsning 2, MOD(a, b) + ABS(b) blev returneret for tilfælde, hvor MOD(a, b) < 0 . Bemærk, at MOD(a, b) + ABS(b) = MOD(a, b) + ABS(b) * 1 when MOD(a, b) < 0 .

I modsætning hertil returnerer du MOD(a, b) når MOD(a, b) >= 0 . Bemærk, at MOD(a, b) = MOD(a, b) + ABS(b) * 0 when MOD(a, b) >= 0 .

Så vi kan gange ABS(b) ved et udtryk, der er lig med 1 for en negativ MOD(a, b) og 0 for en ikke-negativ MOD(a, b) . Siden MOD(a, b) er altid et heltal, udtrykket MOD(a, b) + 0.5 er altid positiv for MOD(a, b) ≥ 0 og negativ for MOD(a, b) < 0 . Du kan bruge ethvert positivt tal mindre end 1 i stedet for 0.5 .

Tegnfunktionen SIGN() returnerer 1 hvis argumentet er strengt positivt, -1 hvis det er strengt negativt, og 0 hvis det er lig med 0 . Du har dog brug for noget, der kun returnerer 0 og 1 , ikke 1 og -1 . Sådan løser du dette:

(1 - 1) / 2 = 0

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

Derefter det korrekte udtryk, som du multiplicerer ABS(b) med er:

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

Så hele formlen er:

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


  1. Undgå at navngive brugerlagrede procedurer SP% eller SP_%

  2. Evaluering, når et udtryk i en forespørgsel evalueres

  3. Sådan fjerner du "X Rows Selected" i SQLcl &SQL*Plus (Oracle)

  4. Håndtering af frødata i R12.2 online patching