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

Остатъкът в PostgreSQL, MS SQL Server, MySQL и SQLite

Проблем:

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

Пример:

В таблицата 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,
  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.

Точно така е a % b работи за неотрицателните дивиденти в колоната a :

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

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

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

Очевидно се показва грешка, ако делителят b е 0 , защото не можете да разделите на 0 .

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

-2 % 5 връща -2 когато трябва да върне 3 .

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

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

SELECT
  a,
  b,
  CASE WHEN a % b >= 0
    THEN a % b
  ELSE
    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 строителство. Ако a % b е неотрицателен, остатъкът е просто a % b . В противен случай трябва да коригираме резултата, върнат от a % b .

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

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

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

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

Разбира се, ако b = 0 , пак ще получите грешка.

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

SELECT
  a,
  b,
  a % b + ABS(b) * (1 - SIGN(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 , използвайте по-сложна едноредова математическа формула:

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

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

Така че можем да умножим ABS(b) чрез израз, равен на 1 за отрицателни стойности на a % b и 0 за неотрицателни стойности на a % b . Тъй като a % b винаги е цяло число, изразът a % b + 0.5 винаги е положителен за a % b >= 0 и отрицателен за 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(a % b + 0.5)) / 2

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

a % b + ABS(b) * (1 - SIGN(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. PHP PDO подготвени изявления

  2. Архивирайте вашите MySQL бази данни

  3. Примери за MySQL SOUNDEX().

  4. Как мога да вмъкна много редове в MySQL таблица и да върна новите идентификатори?

  5. Как да създавате и поддържате MySQL бази данни в cPanel