Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Cách nhận lời nhắc bằng MOD () trong PostgreSQL, MS SQL Server và MySQL

Vấn đề:

Bạn muốn tìm phần còn lại (không âm).

Ví dụ:

Trong bảng numbers , bạn có hai cột số nguyên:ab .

a b
9 3
5 3
2 3
0 3
-2 3
-5 3
-9 3
5 -3
-5 -3
5 0
0 0

Bạn muốn tính phần còn lại từ việc chia a bởi b . Mỗi phần còn lại phải là một giá trị số nguyên không âm nhỏ hơn b .

Giải pháp 1 (không hoàn toàn đúng):

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

Kết quả là:

a b phần còn lại
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 lỗi
0 0 lỗi

Thảo luận:

Giải pháp này hoạt động chính xác nếu a không âm. Tuy nhiên, khi nó âm, nó không tuân theo định nghĩa toán học về phần còn lại.

Về mặt khái niệm, phần còn lại là phần còn lại sau phép chia số nguyên của a bởi b . Về mặt toán học, phần dư của hai số nguyên là một số nguyên không âm nhỏ hơn ước số b . Chính xác hơn, nó là một số r∈ {0,1, ..., b - 1} mà tồn tại một số nguyên k sao cho a =k * b + r . Ví dụ:

5 = 1 * 3 + 2 , vì vậy phần còn lại của 5 và 3 bằng 2 .

9 = 3 * 3 + 0 , vì vậy phần còn lại của 9 và 3 bằng 0 .

5 = (-1) * (-3) + 2 , vì vậy phần còn lại của 5 và -3 bằng 2 .

Đây là cách MOD(a, b) hoạt động cho cổ tức không âm trong cột a . Rõ ràng, một lỗi được hiển thị nếu số chia b0 , bởi vì bạn không thể chia cho 0 .

Lấy phần dư đúng là vấn đề khi số cổ tức a là một số âm. Rất tiếc, MOD(a, b) có thể trả về giá trị âm khi a là âm. Ví dụ:

MOD(-2, 5) trả về -2 khi nào nó sẽ trả về 3 .

MOD(-5, -3) trả về -2 khi nào nó sẽ trả về 1 .

Giải pháp 2 (đúng cho tất cả các số):

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

Kết quả là:

a b phần còn lại
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 lỗi
0 0 lỗi

Thảo luận:

Để tính phần còn lại của phép chia giữa bất kỳ hai số nguyên (âm hoặc không âm), bạn có thể sử dụng CASE WHEN sự thi công. Khi MOD(a, b) là không âm, phần còn lại chỉ đơn giản là MOD(a, b) . Nếu không, chúng tôi phải sửa kết quả trả về bởi MOD(a, b) .

Làm cách nào để bạn lấy được phần còn lại chính xác khi MOD() trả về một giá trị âm? Bạn nên thêm giá trị tuyệt đối của ước số vào MOD(a, b) . Đó là, hãy đặt nó thành MOD(a, b) + ABS(b) :

MOD(-2, 5) trả về -2 khi nào nó sẽ trả về 3 . Bạn có thể sửa lỗi này bằng cách thêm 5 .

MOD(-5, -3) trả về -2 khi nào nó sẽ trả về 1 . Bạn có thể sửa lỗi này bằng cách thêm 3 .

Khi MOD(a, b) trả về một số âm, CASE WHEN kết quả phải là MOD(a, b) + ABS(b) . Đây là cách chúng tôi nhận được Giải pháp 2. Nếu bạn cần cập nhật về cách ABS() hàm hoạt động, hãy xem sách nấu ăn Cách tính giá trị tuyệt đối trong SQL.

Tất nhiên, bạn vẫn không thể chia bất kỳ số nào cho 0 . Vì vậy, nếu b = 0 , bạn sẽ gặp lỗi.

Giải pháp 3 (đúng cho tất cả các số):

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

Kết quả là:

a b phần còn lại
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 lỗi
0 0 lỗi

Thảo luận:

Có một cách khác để giải quyết vấn đề này. Thay vì CASE WHEN , sử dụng công thức toán học một dòng phức tạp hơn:

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

Trong Giải pháp 2, MOD(a, b) + ABS(b) được trả về cho các trường hợp khi MOD(a, b) < 0 . Lưu ý rằng MOD(a, b) + ABS(b) = MOD(a, b) + ABS(b) * 1 when MOD(a, b) < 0 .

Ngược lại, bạn trả về MOD(a, b) khi MOD(a, b) >= 0 . Lưu ý rằng MOD(a, b) = MOD(a, b) + ABS(b) * 0 when MOD(a, b) >= 0 .

Vì vậy, chúng ta có thể nhân ABS(b) bởi một biểu thức bằng 1 cho MOD(a, b) phủ định và 0 cho MOD(a, b) không âm . Kể từ MOD(a, b) luôn là một số nguyên, biểu thức MOD(a, b) + 0.5 luôn dương cho MOD(a, b) ≥ 0 và phủ định cho MOD(a, b) < 0 . Bạn có thể sử dụng bất kỳ số dương nào nhỏ hơn 1 thay vì 0.5 .

Hàm ký SIGN() trả về 1 nếu đối số của nó là đúng, -1 nếu nó hoàn toàn phủ định và 0 nếu nó bằng 0 . Tuy nhiên, bạn cần thứ gì đó chỉ trả về 01 , không phải 1-1 . Đây là cách bạn sửa lỗi này:

(1 - 1) / 2 = 0

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

Sau đó, biểu thức chính xác mà bạn nhân với ABS(b) là:

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

Vì vậy, toàn bộ công thức là:

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. Thay thế chuỗi MySQL

  2. Cách hoạt động của hàm UCASE () trong MySQL

  3. Left Outer Join không trả về tất cả các hàng từ bảng bên trái của tôi?

  4. Các lớp lồng nhau - CustomRowMapper !! Nó không còn là một vấn đề nữa !! - Phần 1

  5. Cách khôi phục MySQL Galera Cluster từ một Slave không đồng bộ