Trước MySQL 5.7, mặc định là cho phép nhóm group by
. Có nghĩa là bạn có thể có một nhóm theo (sử dụng các hàm tổng hợp như sum
và max
và count
và group_concat
) với các cột không được tổng hợp khác (hãy gọi chúng là NON AGGS
) như 3 đầu tiên của bạn được hiển thị không phải tất cả một phần của nhóm group by
mệnh đề. Nó cho phép nó nhưng kết quả thường sẽ diễn ra như thế này:
-
Nó hoạt động tốt vì bạn biết rõ dữ liệu của mình và đang cố gắng đạt được sự khác biệt
-
Nó hoạt động tệ hại bởi vì nó là một snafu
Trước ngày 5.7, ONLY_FULL_GROUP_BY
tồn tại nhưng nó đã bị TẮT theo mặc định.
Vì vậy, trong MySQL 5.7 cùng với ONLY_FULL_GROUP_BY
mặc định là BẬT. Như vậy nếu bạn cố gắng một nhóm theo, nhưng với không phải tất cả NON AGGS
trong nhóm group by
, bạn sẽ gặp lỗi.
Hãy xem xét vấn đề sau trong 5.6 dưới đây:
create table thing
( col1 int not null,
col2 int not null,
age int not null
);
insert thing(col1,col2,age) values
(1,2,10),
(1,3,20),
(2,3,20),
(2,2,10);
select col1,col2,max(age) from thing group by col1;
+------+------+----------+
| col1 | col2 | max(age) |
+------+------+----------+
| 1 | 2 | 20 |
| 2 | 3 | 20 |
+------+------+----------+
Những gì xảy ra ở trên không phải là tất cả NON AGGS
nằm trong nhóm group by
. Nó trả về (tuổi) tối đa bằng col1. Nhưng kể từ khi col2
không có trong nhóm group by
, nó đã sử dụng Chỉ mục cụm hoặc Thứ tự vật lý và vô tình có lẽ (một lỗi, một sai lầm), giá trị sai cho col2. Tùy thuộc vào ý định của bạn hoặc biết dữ liệu của bạn hoặc thậm chí quan tâm. Động cơ không quan tâm; có lẽ bạn làm.
Để tránh những lỗi thường gặp này hoặc việc trả về dữ liệu không cố ý, MySQL 5.7 bật ONLY_FULL_GROUP_BY
theo mặc định.
Trong trường hợp của bạn, các hàng sai đang tạo nên kết quả của bạn có lẽ cho cột 2 và 3.
Xem Trang hướng dẫn có tên Xử lý MySQL của GROUP BY .
Ví dụ 2
-- drop table if exists person;
create table person
( id int auto_increment primary key,
firstName varchar(100) not null,
lastName varchar(100) not null
);
-- drop table if exists fruitConsumed;
create table fruitConsumed
( id int auto_increment primary key,
theDate date not null,
fruitId int not null, -- does not really matter. Say, 1=apple, 2=orange from some other table
personId int not null,
qty int not null
);
-- truncate table person;
insert person (firstName,lastName) values
('Dirk','Peters'),
('Dirk','Smith'),
('Jane','Billings');
-- truncate table fruitConsumed;
insert fruitConsumed (theDate,fruitId,personId,qty) values
('2016-10-31',1,1,2),
('2016-10-31',2,1,5),
('2016-10-31',2,2,12),
('2016-11-02',2,2,3);
Truy vấn:
select p.firstName,p.lastName,sum(fc.qty)
from person p
join fruitConsumed fc
on fc.personId=p.id
group by p.firstName,p.lastName;
+-----------+----------+-------------+
| firstName | lastName | sum(fc.qty) |
+-----------+----------+-------------+
| Dirk | Peters | 7 |
| Dirk | Smith | 15 |
+-----------+----------+-------------+
Phần trên hoạt động tốt trên MySQL 5.6 và 5.7 bất kể cài đặt cho ONLY_FULL_GROUP_BY
bây giờ hãy xem xét
select p.firstName,p.lastName,sum(fc.qty)
from person p
join fruitConsumed fc
on fc.personId=p.id
group by p.firstName;
+-----------+----------+-------------+
| firstName | lastName | sum(fc.qty) |
+-----------+----------+-------------+
| Dirk | Peters | 22 |
+-----------+----------+-------------+
Ở trên thường được chấp nhận trên MySQL 5.6 mà không có ONLY_FULL_GROUP_BY
được bật và không thành công vào ngày 5.7 với ONLY_FULL_GROUP_BY
đã bật (lỗi 1055). Kết quả trên về cơ bản là vô nghĩa. Nhưng dưới đây nó được giải thích phần nào:
Chúng ta biết rằng Dirk, một Dirk, chỉ một Dirk, là người duy nhất sống sót sau cuộc tham gia bên trong. Có 2 Dirks. Nhưng vì nhóm group by p.firstName
, chúng ta chỉ còn lại một Dirk. Chúng tôi cần một lastName
. Do không tuân theo
Tiêu chuẩn SQL, MySQL có thể cho phép điều này với ONLY_FULL_GROUP_BY
đã tắt. Vì vậy, nó chỉ chọn bất kỳ LastName cũ nào. Chà, cái đầu tiên nó tìm thấy và cái đó nằm trong bộ nhớ cache hoặc cái trong thứ tự vật lý.
Và nó đã đi cùng với Peters. Tổng số lượng trái cây dành cho tất cả các Dirks.
Vì vậy, nếu bạn viết mã như thế này, ONLY_FULL_GROUP_BY
không tuân thủ cho bạn vô nghĩa.
Và như đã nêu, MySQL 5.7 được mặc định không cho phép điều này. Nhưng nó có thể điều chỉnh theo cách cũ nếu bạn chọn.
Bạn nên sửa các truy vấn của mình và để lại ONLY_FULL_GROUP_BY
như đã được kích hoạt.