MySQL非标准SQL写法问题记录 博客分类: MySQL mysqlGROUP BY
程序员文章站
2024-02-25 20:38:57
...
如下SQL:
上述执行结果总数是:2525行
但如果去掉最后面的:GROUP BY t.message_id,t.product_id 后执行结果却只有一条记录,这显然不符合正常逻辑(正常情况下查询结果是不低于2525行的),
造成此问题原因是上述SQL是非标准SQL,标准SQL要求中要求 SELECT后的查询字段必须和GROUP BY后的字段是相同的,即不能多也不能少!
备注:
1.在group by 里的列,可以直接出现在结果列(也可以少)。
2.不在group by 里的列,在经过聚合函数计算后可以出现在结果列(也可以多)。
PS:Oracle中是不支持此非标准写法的。
附加:
根据SQL92国际标准:
http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
If T is a grouped table, then each <column reference> in each <value
expression> that references a column of T shall reference a grouping
column or be specified within a <set function specification>.
简单的说,如果一个查询用了 group by,那么 select 可选择的 列 有两个可能 1. group by
中指定的列(或者其计算值),2. 聚合函数计算后的其它(非group by指定的)列。
而 MySQL 自作聪明(关闭ONLY_FULL_GROUP_BY),不符合国际标准,容忍了我们犯错,这也是引起我们自己混乱的原因。
举个例子:
gender age
男 11
女 22
男 33
这语句你们指望得到什么结果?
是:
男 11
女 22
还是:
女 22
男 33
这本来就不是个正确的SQL语句!
正确的语句应该改为这样:
也就是将非group by的列放入某个聚合函数里。
建议以后写语句严格要求自己,不要让MySQL将我们带入歧途!
可能的话将ONLY_FULL_GROUP_BY打开。
MySQL查询原理及其慢查询优化案例
SELECT t.message_id, t.product_id, t.drug_code, t.analysis_result_type, t.analysis_type, t.severity, ( CASE t.drug_code WHEN '001' THEN (SELECT sd.chineseProductName FROM `149wuhu_platform`.tb_product sd WHERE sd.id = t.product_id) ELSE b.drug_id END ) product_name, IF( b.source = '配伍禁忌' AND b.message_id LIKE '10%', t.message, b.message ) message, SUM(COUNT) AS amount, '1' AS dataType, IFNULL(b.rule_type, 0) rule_type, IFNULL(c.apply_status, 0) apply_status, b.status_recipe alert_status FROM opt_alertmessage_statistic AS t INNER JOIN `149wuhu_platform`.tb_drug_rule_message b ON t.message_id = b.message_id LEFT JOIN `149wuhu_platform`.base_message_review c ON c.message_id = t.message_id AND c.apply_user_id = 1 WHERE t.key_date >= '2016-03-01' AND t.key_date <= '2016-04-05' AND (t.zone_id IN (2, 3, 4, 5, 6, 7, 8, 9)) GROUP BY t.message_id,t.product_id
上述执行结果总数是:2525行
但如果去掉最后面的:GROUP BY t.message_id,t.product_id 后执行结果却只有一条记录,这显然不符合正常逻辑(正常情况下查询结果是不低于2525行的),
造成此问题原因是上述SQL是非标准SQL,标准SQL要求中要求 SELECT后的查询字段必须和GROUP BY后的字段是相同的,即不能多也不能少!
备注:
1.在group by 里的列,可以直接出现在结果列(也可以少)。
2.不在group by 里的列,在经过聚合函数计算后可以出现在结果列(也可以多)。
PS:Oracle中是不支持此非标准写法的。
附加:
根据SQL92国际标准:
http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
If T is a grouped table, then each <column reference> in each <value
expression> that references a column of T shall reference a grouping
column or be specified within a <set function specification>.
简单的说,如果一个查询用了 group by,那么 select 可选择的 列 有两个可能 1. group by
中指定的列(或者其计算值),2. 聚合函数计算后的其它(非group by指定的)列。
而 MySQL 自作聪明(关闭ONLY_FULL_GROUP_BY),不符合国际标准,容忍了我们犯错,这也是引起我们自己混乱的原因。
举个例子:
gender age
男 11
女 22
男 33
这语句你们指望得到什么结果?
SELECT gender,age FROM USER GROUP BY gender
是:
男 11
女 22
还是:
女 22
男 33
这本来就不是个正确的SQL语句!
正确的语句应该改为这样:
SELECT gender,MIN(age) FROM USER GROUP BY gender
也就是将非group by的列放入某个聚合函数里。
建议以后写语句严格要求自己,不要让MySQL将我们带入歧途!
可能的话将ONLY_FULL_GROUP_BY打开。
MySQL查询原理及其慢查询优化案例
上一篇: 双token实现token超时策略示例