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

MySQL:Tổng số NHÓM BẰNG CÁCH CÓ ROLLUP gây tò mò

Bởi vì bạn không CHỌN mục mà bạn đang NHÓM THEO. Nếu bạn nói:

GROUP BY c.printable_name

Bạn sẽ nhận được NULL như mong đợi. Tuy nhiên, bạn đang nhóm theo một cột khác nên MySQL không biết rằng printable_name đang tham gia vào một nhóm cuộn lên và chọn bất kỳ giá trị cũ nào từ cột đó, trong phần nối của tất cả đăng ký. (Vì vậy, có thể bạn sẽ thấy các quốc gia khác ngoài Uzbekistan.)

Đây là một phần của một vấn đề lớn hơn với MySQL được cho phép đối với những gì bạn có thể CHỌN trong một truy vấn GROUP BY. Ví dụ, bạn có thể nói:

SELECT gender FROM registrations GROUP BY country;

và MySQL sẽ vui vẻ chọn một trong các giá trị giới tính cho đăng ký từ mỗi quốc gia, mặc dù không có mối liên hệ nhân quả trực tiếp (hay còn gọi là “phụ thuộc chức năng”) giữa quốc gia và giới tính. Các DBMS khác sẽ từ chối lệnh trên với lý do không đảm bảo có một giới tính cho mỗi quốc gia. (*)

Bây giờ, cái này:

SELECT c.printable_name AS 'Country', count(*) AS '#' 
FROM registrations r 
INNER JOIN country c ON r.country = c.country_id 
GROUP BY country

được, vì có sự phụ thuộc chức năng giữa r.country và c.printable_name (giả sử bạn đã mô tả chính xác country_id của mình dưới dạng TỪ KHÓA CHÍNH).

Tuy nhiên, phần mở rộng WITH ROLLUP của MySQL có một chút khó khăn trong cách nó hoạt động. Ở cuối giai đoạn hàng cuộn lên, nó chạy trên toàn bộ tập hợp kết quả nhóm trước để lấy các giá trị của nó và sau đó đặt cột theo nhóm thành NULL. Nó cũng không làm rỗng các cột khác có phụ thuộc hàm vào cột đó. Có lẽ nên làm như vậy, nhưng MySQL hiện không thực sự hiểu toàn bộ về các phụ thuộc hàm.

Vì vậy, nếu bạn chọn c.printable_name, nó sẽ hiển thị cho bạn giá trị tên quốc gia nào mà nó được chọn ngẫu nhiên và nếu bạn chọn c.country_id, nó sẽ hiển thị cho bạn bất kỳ ID quốc gia nào mà nó được chọn ngẫu nhiên - mặc dù c.country_id là tiêu chí tham gia, vì vậy phải giống như r.country, là NULL!

Những gì bạn có thể làm để giải quyết vấn đề là:

  • thay vào đó nhóm theo printable_name; Sẽ ổn nếu printable_names là duy nhất hoặc
  • chọn “r.country” cũng như printable_name và kiểm tra xem có phải là NULL hay không, hay
  • quên VỚI ROLLUP và thực hiện một truy vấn riêng cho tổng cuối. Quá trình này sẽ chậm hơn một chút nhưng cũng sẽ tuân thủ ANSI SQL-92 để ứng dụng của bạn có thể hoạt động trên các cơ sở dữ liệu khác.

(*:MySQL có tùy chọn SQL_MODE ONLY_FULL_GROUP_BY được cho là giải quyết vấn đề này, nhưng nó đã đi quá xa và chỉ cho phép bạn chọn các cột từ GROUP BY, không phải các cột có phụ thuộc hàm vào GROUP BY. Vì vậy, nó cũng sẽ làm cho các truy vấn hợp lệ bị lỗi, khiến nó thường trở nên vô dụng.)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách đặt múi giờ cơ sở dữ liệu trong application.ini

  2. Sự khác biệt giữa BIT và TINYINT trong MySQL là gì?

  3. Cập nhật hàng loạt Sqlalchemy trong MySQL hoạt động rất chậm

  4. Làm cách nào để hiển thị lỗi cho truy vấn MySQLi của tôi?

  5. Làm cách nào để kết nối lại các kết nối bị mất với EclipseLink?