Antes do MySQL 5.7, o padrão era permitir
group by
não FULL . O que significa que você pode ter um grupo por (que usa funções agregadas como sum
e max
e count
e group_concat
) com outras colunas não agregadas (vamos chamá-las de NON AGGS
) como seus 3 primeiros mostrados nem todos parte do seu group by
cláusula. Permitiu, mas os resultados normalmente funcionariam assim:-
Funcionou muito bem porque você conhece bem seus dados e está tentando alcançar um
-
Deu muito certo porque foi um snafu
Antes de 5.7,
ONLY_FULL_GROUP_BY
existia, mas estava DESLIGADO por padrão. Então no MySQL 5.7 vem o
ONLY_FULL_GROUP_BY
padrão LIGADO. Assim, se você tentar agrupar por, mas com nem todos o NON AGGS
no group by
cláusula, você obteria um erro. Considere o seguinte problema em 5.6 abaixo:
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 |
+------+------+----------+
O que acontece acima não é tudo
NON AGGS
estão no group by
. Ele retorna o max(idade) por col1. Mas como col2
não estava no group by
, ele usou o Cluster Index ou Physical Ordering e trouxe, inadvertidamente, talvez (um snafu, um erro), o valor errado para col2. Dependendo de suas intenções ou conhecendo seus dados ou até mesmo se importando. O motor não se importava; talvez você faça. Para evitar esses erros comuns ou retorno de dados inadvertido, o MySQL 5.7 ativa
ONLY_FULL_GROUP_BY
por padrão. No seu caso, as linhas erradas estão compondo seus resultados presumivelmente para as colunas 2 e 3.
Consulte a página do manual intitulada Manipulação MySQL de GROUP BY .
Exemplo 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);
Inquerir:
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 |
+-----------+----------+-------------+
O acima funciona muito bem no MySQL 5.6 e 5.7, independentemente da configuração para
ONLY_FULL_GROUP_BY
agora considere
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 |
+-----------+----------+-------------+
O acima é geralmente aceitável no MySQL 5.6 sem
ONLY_FULL_GROUP_BY
ativado e falha em 5.7 com ONLY_FULL_GROUP_BY
habilitado (erro 1055). A saída acima é basicamente sem sentido. Mas abaixo é explicado um pouco:Sabemos que Dirk, um Dirk, apenas um Dirk, é o único a sobreviver à junção interna. Existem 2 Dirks. Mas por causa do
group by p.firstName
, ficamos com apenas um Dirk. Precisamos de um lastName
. Devido à não conformidade como padrão SQL, o MySQL pode permitir isso com
ONLY_FULL_GROUP_BY
desligado. Então, ele apenas escolhe qualquer sobrenome antigo. Bem, o primeiro que ele encontra, e que está no cache ou no ordenamento físico. E foi com Peters. A soma da contagem de frutas é para todos os Dirks.
Portanto, se você codificar assim, a não conformidade não-
ONLY_FULL_GROUP_BY
te dá um gabarito. E como dito, o MySQL 5.7 vem por padrão para não permitir isso. Mas é ajustável à maneira antiga, se você escolher.
É altamente recomendável que você corrija suas consultas e deixe
ONLY_FULL_GROUP_BY
como habilitado.