Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да получите остатък с помощта на MOD() в PostgreSQL, MS SQL Server и MySQL

Проблем:

Искате да намерите (неотрицателния) остатък.

Пример:

В таблицата numbers , имате две колони с цели числа: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

Искате да изчислите остатъците от разделянето на a от b . Всеки остатък трябва да бъде неотрицателна стойност, по-малка от b .

Решение 1 (не е напълно правилно):

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

Резултатът е:

a b остатък
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 грешка
0 0 грешка

Дискусия:

Това решение работи правилно, ако a е неотрицателно. Когато обаче е отрицателен, той не следва математическата дефиниция на остатъка.

Концептуално остатъкът е това, което остава след целочислено деление на a от b . Математически, остатъкът от две цели числа е цяло неотрицателно число, което е по-малко от делителя b . По-точно, това е число r∈{0,1,...,b - 1}, за което съществува някакво цяло число k, такова че a =k * b + r . Напр.:

5 = 1 * 3 + 2 , така че остатъкът от 5 и 3 е равен на 2 .

9 = 3 * 3 + 0 , така че остатъкът от 9 и 3 е равен на 0 .

5 = (-1) * (-3) + 2 , така че остатъкът от 5 и -3 е равен на 2 .

Ето как MOD(a, b) работи за неотрицателните дивиденти в колоната a . Очевидно се показва грешка, ако делителят b е 0 , защото не можете да разделите на 0 .

Получаването на правилния остатък е проблематично, когато дивидентът a е отрицателно число. За съжаление, MOD(a, b) може да върне отрицателна стойност, когато a е отрицателно. Напр.:

MOD(-2, 5) връща -2 когато трябва да върне 3 .

MOD(-5, -3) връща -2 когато трябва да върне 1 .

Решение 2 (правилно за всички числа):

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

Резултатът е:

a b остатък
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 грешка
0 0 грешка

Дискусия:

За изчисляване на остатъка от деление между всякакво две цели числа (отрицателни или неотрицателни), можете да използвате CASE WHEN строителство. Когато MOD(a, b) е неотрицателен, остатъкът е просто MOD(a, b) . В противен случай трябва да коригираме резултата, върнат от MOD(a, b) .

Как да получите правилния остатък, когато MOD() връща отрицателна стойност? Трябва да добавите абсолютната стойност на делителя към MOD(a, b) . Тоест направете го MOD(a, b) + ABS(b) :

MOD(-2, 5) връща -2 когато трябва да върне 3 . Можете да коригирате това, като добавите 5 .

MOD(-5, -3) връща -2 когато трябва да върне 1 . Можете да коригирате това, като добавите 3 .

Когато MOD(a, b) връща отрицателно число, CASE WHEN резултатът трябва да бъде MOD(a, b) + ABS(b) . Ето как получаваме Решение 2. Ако имате нужда от опресняване на това как ABS() функцията работи, погледнете готварската книга Как да изчислите абсолютна стойност в SQL.

Разбира се, все още не можете да разделите никое число на 0 . Така че, ако b = 0 , ще получите грешка.

Решение 3 (правилно за всички числа):

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

Резултатът е:

a b остатък
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 грешка
0 0 грешка

Дискусия:

Има и друг начин за решаване на този проблем. Вместо CASE WHEN , използвайте по-сложна едноредова математическа формула:

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

В решение 2, MOD(a, b) + ABS(b) беше върнат за случаи, когато MOD(a, b) < 0 . Обърнете внимание, че MOD(a, b) + ABS(b) = MOD(a, b) + ABS(b) * 1 when MOD(a, b) < 0 .

За разлика от това, вие връщате MOD(a, b) когато MOD(a, b) >= 0 . Обърнете внимание, че MOD(a, b) = MOD(a, b) + ABS(b) * 0 when MOD(a, b) >= 0 .

Така че можем да умножим ABS(b) чрез израз, равен на 1 за отрицателен MOD(a, b) и 0 за неотрицателен MOD(a, b) . Тъй като MOD(a, b) винаги е цяло число, изразът MOD(a, b) + 0.5 винаги е положителен за MOD(a, b) ≥ 0 и отрицателен за MOD(a, b) < 0 . Можете да използвате всяко положително число, по-малко от 1 вместо 0.5 .

Знаковата функция SIGN() връща 1 ако аргументът му е строго положителен, -1 ако е строго отрицателен, и 0 ако е равно на 0 . Трябва ви обаче нещо, което връща само 0 и 1 , а не 1 и -1 . Ето как да коригирате това:

(1 - 1) / 2 = 0

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

След това правилният израз, по който умножавате ABS(b) е:

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

И така, цялата формула е:

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. MySQL избира координати в обхват

  2. SQL таблица с запис в списък срещу SQL таблица с ред за всеки запис

  3. Как да вмъкна няколко реда от масив с помощта на рамката CodeIgniter?

  4. Запазване на данни на арабски в MySQL база данни

  5. Работа с MySQL TIMESTAMP колони в SQL Server