繁体   English   中英

在MySQL 5.7和5.6之间具有子查询的不同结果

[英]Different results for having with subquery between MySQL 5.7 and 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子句在较新版本中被忽略。

这个地区有一些卑诗省吗?

这是问题的症结所在:

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

这里的问题是,不清楚每个id使用了哪个 usedforce_option值。

我建议,尽管您看到了什么,但在计算在MySQL 5.7.19上运行的查询的每个id组时,MySQL实际上使用的非零值的usedforce_option值为1 对于在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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM