在MySQL 5.7和5.6之间使用子查询的结果不同

时间:2017-09-28 11:15:49

标签: mysql mysql-5.7 mysql-5.6

查询:

SELECT
  MIN(main_table.id) as id,
  COALESCE(used_options.used, 0)           AS used,
  COALESCE(forced_options.force_option, 0) AS force_option
FROM main_table
  LEFT JOIN (
              SELECT
                used_options.id id,
                1 AS            used
              FROM main_table AS used_options
              WHERE used_options.id = 20
            ) AS used_options
    ON used_options.id = main_table.id
  LEFT JOIN (
              SELECT
                test.id,
                1 AS force_option
              FROM main_table AS test
              WHERE test.id = 10
            ) AS forced_options
    ON forced_options.id = main_table.id
 GROUP BY main_table.id
 HAVING (used IS NOT NULL AND used > 0)
    OR (force_option IS NOT NULL AND force_option = 1);

在MySQL 5.7.19(docker image mysql:5.7.19)上,我得到了:

+-----+------+--------------+
| id  | used | force_option |
+-----+------+--------------+
|   1 |    0 |            0 |
|   2 |    0 |            0 |
|   3 |    0 |            0 |
|   4 |    0 |            0 |
|   5 |    0 |            0 |
|   6 |    0 |            0 |
|  10 |    0 |            1 |
|  20 |    1 |            0 |
+-----+------+--------------+

在MySQL 5.6.37上(docker image mysql:5.6.37)我得到:

+-----+------+--------------+
| id  | used | force_option |
+-----+------+--------------+
|  10 |    0 |            1 |
|  20 |    1 |            0 |
+-----+------+------+------+--------------+

用于创建和填充表格的示例数据:

CREATE TABLE main_table
(
     id   INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
     fk_1 INT         NOT NULL,
     fk_2 VARCHAR(45) NOT NULL
);

INSERT INTO main_table (id, fk_1, fk_2) VALUES (1, 1, '2');
INSERT INTO main_table (id, fk_1, fk_2) VALUES (2, 1, '4');
INSERT INTO main_table (id, fk_1, fk_2) VALUES (3, 1, '5');
INSERT INTO main_table (id, fk_1, fk_2) VALUES (4, 1, '7');
INSERT INTO main_table (id, fk_1, fk_2) VALUES (5, 1, '10');
INSERT INTO main_table (id, fk_1, fk_2) VALUES (6, 1, '20');
INSERT INTO main_table (id, fk_1, fk_2) VALUES (10, 1, '34');
INSERT INTO main_table (id, fk_1, fk_2) VALUES (20, 1, '23');

这两个版本的MySQL之间发生了什么变化?看起来HAVING子句在此特定查询的较新版本中被忽略。

这个区域有一些BC?

1 个答案:

答案 0 :(得分:1)

以下是问题的症结所在:

GROUP BY main_table.id

您按一列进行分组,但选择了许多非聚合列:

SELECT
    main_table.id,
    main_table.fk_2,
    main_table.fk_1,
    COALESCE(used_options.used, 0)           AS used,
    COALESCE(forced_options.force_option, 0) AS force_option

此处的问题是, usedforce_option值被用于每个id并不明确。

我建议,尽管你看到了,但在为查询计算每个used组时,MySQL实际上对force_option1 id值使用了非零值在MySQL 5.7.19上运行。对于在MySQL 5.6.37上运行的查询,这没有发生,并且HAVING子句除了两条记录之外的所有条目都被过滤掉了,这是我们通过浏览表数据所期望的。

这里真正的罪魁祸首是MySQL的ONLY_FULL_GROUP_BY模式,当关闭时,它允许这些不严格的查询选择也使用GROUP BY的非聚合列。最好的长期修复是您重构查询,这样您就不需要选择非聚合列。

https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

相关问题