Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Cara Mendapatkan Sisa Menggunakan MOD() di PostgreSQL, MS SQL Server, dan MySQL

Masalah:

Anda ingin mencari sisa (non-negatif).

Contoh:

Dalam tabel numbers , Anda memiliki dua kolom bilangan bulat:a dan 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

Anda ingin menghitung sisa dari pembagian a oleh b . Setiap sisa harus berupa nilai bilangan bulat non-negatif yang lebih kecil dari b .

Solusi 1 (tidak sepenuhnya benar):

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

Hasilnya adalah:

a b sisa
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 kesalahan
0 0 kesalahan

Diskusi:

Solusi ini bekerja dengan benar jika a adalah non-negatif. Namun, jika negatif, tidak mengikuti definisi matematika dari sisanya.

Secara konseptual, sisa adalah apa yang tersisa setelah pembagian bilangan bulat a oleh b . Secara matematis, sisa dua bilangan bulat adalah bilangan bulat tak negatif yang lebih kecil dari pembagi b . Lebih tepatnya, itu adalah angka r∈{0,1,...,b - 1} dimana terdapat beberapa bilangan bulat k sehingga a =k * b + r . Mis.:

5 = 1 * 3 + 2 , jadi sisa 5 dan 3 sama dengan 2 .

9 = 3 * 3 + 0 , jadi sisa 9 dan 3 sama dengan 0 .

5 = (-1) * (-3) + 2 , jadi sisa 5 dan -3 sama dengan 2 .

Begini caranya MOD(a, b) bekerja untuk dividen non-negatif di kolom a . Jelas, kesalahan ditampilkan jika pembagi b adalah 0 , karena Anda tidak dapat membagi dengan 0 .

Mendapatkan sisa yang benar bermasalah ketika dividen a adalah angka negatif. Sayangnya, MOD(a, b) dapat mengembalikan nilai negatif ketika a negatif. Mis.:

MOD(-2, 5) mengembalikan -2 kapan seharusnya mengembalikan 3 .

MOD(-5, -3) mengembalikan -2 kapan seharusnya mengembalikan 1 .

Solusi 2 (benar untuk semua angka):

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

Hasilnya adalah:

a b sisa
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 kesalahan
0 0 kesalahan

Diskusi:

Untuk menghitung sisa pembagian antara apa saja dua bilangan bulat (negatif atau non-negatif), Anda dapat menggunakan CASE WHEN konstruksi. Ketika MOD(a, b) tidak negatif, sisanya hanya MOD(a, b) . Jika tidak, kita harus memperbaiki hasil yang dikembalikan oleh MOD(a, b) .

Bagaimana Anda mendapatkan sisa yang benar ketika MOD() mengembalikan nilai negatif? Anda harus menambahkan nilai absolut dari pembagi ke MOD(a, b) . Yaitu, buat MOD(a, b) + ABS(b) :

MOD(-2, 5) mengembalikan -2 kapan seharusnya mengembalikan 3 . Anda dapat memperbaikinya dengan menambahkan 5 .

MOD(-5, -3) mengembalikan -2 kapan seharusnya mengembalikan 1 . Anda dapat memperbaikinya dengan menambahkan 3 .

Ketika MOD(a, b) mengembalikan angka negatif, CASE WHEN hasilnya harus MOD(a, b) + ABS(b) . Beginilah cara kami mendapatkan Solusi 2. Jika Anda membutuhkan penyegaran tentang cara ABS() berfungsi, lihat buku masak Cara menghitung nilai absolut dalam SQL.

Tentu saja, Anda tetap tidak dapat membagi bilangan apa pun dengan 0 . Jadi, jika b = 0 , Anda akan mendapatkan kesalahan.

Solusi 3 (benar untuk semua angka):

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

Hasilnya adalah:

a b sisa
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 kesalahan
0 0 kesalahan

Diskusi:

Ada cara lain untuk mengatasi masalah ini. Alih-alih CASE WHEN , gunakan rumus matematika satu baris yang lebih kompleks:

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

Dalam Solusi 2, MOD(a, b) + ABS(b) dikembalikan untuk kasus ketika MOD(a, b) < 0 . Perhatikan bahwa MOD(a, b) + ABS(b) = MOD(a, b) + ABS(b) * 1 when MOD(a, b) < 0 .

Sebaliknya, Anda mengembalikan MOD(a, b) ketika MOD(a, b) >= 0 . Perhatikan bahwa MOD(a, b) = MOD(a, b) + ABS(b) * 0 when MOD(a, b) >= 0 .

Jadi, kita dapat mengalikan ABS(b) dengan ekspresi yang sama dengan 1 untuk MOD(a, b) negatif dan 0 untuk MOD(a, b) non-negatif . Sejak MOD(a, b) selalu bilangan bulat, ekspresi MOD(a, b) + 0.5 selalu positif untuk MOD(a, b) ≥ 0 dan negatif untuk MOD(a, b) < 0 . Anda dapat menggunakan bilangan positif apa pun yang kurang dari 1 bukannya 0.5 .

Fungsi tanda SIGN() mengembalikan 1 jika argumennya benar-benar positif, -1 jika benar-benar negatif, dan 0 jika sama dengan 0 . Namun, Anda memerlukan sesuatu yang hanya mengembalikan 0 dan 1 , bukan 1 dan -1 . Inilah cara Anda memperbaikinya:

(1 - 1) / 2 = 0

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

Kemudian, ekspresi yang benar untuk mengalikan ABS(b) adalah:

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

Jadi, seluruh rumusnya adalah:

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 di Cloud - Pro dan Kontra Amazon RDS

  2. Bagaimana Fungsi REGEXP_LIKE() Bekerja di MySQL

  3. MySQL Memesan dengan nomor, Nulls terakhir

  4. Impor batas ukuran file di PHPMyAdmin

  5. 1064 kesalahan dalam CREATE TABLE ... TYPE=MYISAM