Prior to MySQL 5.7 the default was to allow non FULL group by
. Which means you can have a group by (that uses aggregate functions like sum
and max
and count
and group_concat
) with other non-aggregated columns (let's call them NON AGGS
) like your first 3 shown not all part of your group by
clause. It allowed it but the results would typically work out like this:
Prior to 5.7, ONLY_FULL_GROUP_BY
existed but it was turned OFF by default.
So in MySQL 5.7 along comes the ONLY_FULL_GROUP_BY
defaulted ON. As such if you attempt a group by, but with not all the NON AGGS
in the group by
clause, you would get an Error.
Consider the following problem in 5.6 below:
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 |
+------+------+----------+
What happens above is not all the NON AGGS
are in the group by
. It returns the max(age) by col1. But since col2
was not in the group by
, it used the Cluster Index or Physical Ordering and brought it, inadvertently perhaps (a snafu, a mistake), the wrong value for col2. Depending on your intentions or knowing your data or even caring. The engine didn't care; perhaps you do.
To avoid these common mistakes or inadvertent data return, MySQL 5.7 turns on ONLY_FULL_GROUP_BY
by default.
In your case, the wrong rows are making up your results presumably for columns 2 and 3.
See the Manual Page entitled MySQL Handling of GROUP BY.
Example 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);
Query:
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 |
+-----------+----------+-------------+
The above works great on MySQL 5.6 and 5.7 regardless of the setting for ONLY_FULL_GROUP_BY
now consider
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 |
+-----------+----------+-------------+
The above is often acceptable on MySQL 5.6 without ONLY_FULL_GROUP_BY
enabled and fails on 5.7 with ONLY_FULL_GROUP_BY
enabled (error 1055). The above output is basically gibberish. But below it is explained somewhat:
We know that Dirk, a Dirk, just one Dirk, is the only one to survive the inner join. There are 2 Dirks. But because of the group by p.firstName
, we are left with just one Dirk. We need a lastName
. Because of the non-conformity to
the SQL Standard, MySQL can allow this with ONLY_FULL_GROUP_BY
turned off. So it just picks any old lastName. Well, the first one it finds, and that is either in cache or the one in the physical ordering.
And it went with Peters. The fruit count sum is for all Dirks.
So if you code like this, the non-conforming non-ONLY_FULL_GROUP_BY
gives you gibberish.
And as stated, MySQL 5.7 ships defaulted to not allowing this. But it is tweakable to the old way if you choose.
It is highly recommended that you fix your queries and leave ONLY_FULL_GROUP_BY
as enabled.