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, 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.
Det er præcis sådan a % b virker for de ikke-negative udbytter i kolonnen a :
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 .
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, a % b kan returnere en negativ værdi, når a er negativ. F.eks.:
-2 % 5 returnerer -2 hvornår den skulle returnere 3 .
-5 % -3 returnerer -2 hvornår den skulle returnere 1 .
Løsning 2 (korrekt for alle tal):
SELECT
a,
b,
CASE WHEN a % b >= 0
THEN a % b
ELSE
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 af enhver to heltal (negative eller ikke-negative), kan du bruge CASE WHEN konstruktion. Hvis a % b er ikke-negativ, er resten blot a % b . Ellers skal vi rette resultatet returneret af a % b .
Hvis a % b returnerer en negativ værdi, skal du tilføje den absolutte værdi af en divisor til a % b . Det vil sige, gør det til a % b + ABS(b) :
-2 % 5 returnerer -2 hvornår den skulle returnere 3 . Du kan rette dette ved at tilføje 5 .
-5 % (-3) returnerer -2 hvornår den skulle returnere 1 . Du kan rette dette ved at tilføje 3 .
Når a % b returnerer en negativ værdi, CASE WHEN resultatet skal være a % b + ABS(b) . Sådan får du 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, hvis b = 0 , får du stadig en fejl.
Løsning 3 (korrekt for alle tal):
SELECT a, b, a % b + ABS(b) * (1 - SIGN(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:
a % b + ABS(b) * (1 - SIGN(a % b + 0.5)) / 2
I løsning 2, a % b + ABS(b) blev returneret for tilfælde, hvor a % b < 0 . Bemærk, at a % b + ABS(b) = a % b + ABS(b) * 1 when a % b < 0 .
Så vi kan gange ABS(b) ved et udtryk, der er lig med 1 for negative værdier af a % b og 0 for ikke-negative værdier på a % b . Siden a % b er altid et heltal, udtrykket a % b + 0.5 er altid positiv for a % b >= 0 og negativ for 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 . Men ingen bekymringer! Sådan løser du dette:
(1 - 1) / 2 = 0
(1 - (-1)) / 2 = 1
Derefter det korrekte udtryk, som du skal gange ABS(b) med er:
(1 - SIGN(a % b + 0.5)) / 2
Så hele formlen er:
a % b + ABS(b) * (1 - SIGN(a % b + 0.5)) / 2