含GROUP BY的MySQL查询返回行数多于无GROUP BY的异常问题
问题原因分析
1. 无GROUP BY时仅返回1条的原因
你的查询里用到了MAX(MA.ldate)这个聚合函数,当没有指定GROUP BY时,MySQL会把整个符合WHERE条件的结果集当成一个单独的分组处理。聚合函数(比如MAX)会将分组内所有行合并计算出一个结果,而SELECT里的其他非聚合列(比如MA.m_app_id、MA.full_name),在MySQL关闭ONLY_FULL_GROUP_BY模式的情况下,会随机从分组内某一行取值。最终整个分组只会输出1条记录,这就是你只得到1行结果的原因。
2. 加GROUP BY PM.id后返回多行的原因
当你加上GROUP BY PM.id,查询会按照PM.id的不同值拆分分组——每个PM.id对应一个独立分组(也就是一个商户)。每个分组会单独计算MAX(MA.ldate),其他非聚合列则从该分组内的行中随机选取(同样是因为宽松模式)。此时返回的行数等于符合WHERE条件的不同PM.id的数量,也就是你预期的商户总数。
注意:你的SQL存在潜在问题
虽然当前查询能运行,但它不符合标准SQL规范:SELECT列表中的非聚合列(比如MA.m_app_id、MA.full_name、MA.service_type)既不在GROUP BY子句中,也没有用聚合函数包裹。在开启ONLY_FULL_GROUP_BY的MySQL环境中,这个查询会直接报错。即使现在能运行,这些列的值也是随机取的,可能和MAX(MA.ldate)对应的那行数据不匹配,结果不可靠。
优化建议
如果你的需求是获取每个商户对应的最新MA记录(即MA.ldate最大的那行),推荐用窗口函数实现,避免GROUP BY带来的随机取值问题:
SELECT id, email, name, mobile, country, status, joined_date, details_status, freeze, blacklist, blacklist_remark, blacklist_adate, app_id, replace_name, ldate, svc_type FROM ( SELECT PM.id AS id, PM.email AS email, PM.name AS name, PM.mobile AS mobile, PM.country AS country, PM.status AS status, PM.cdate AS joined_date, PM.details_status AS details_status, PM.freeze AS freeze, PM.blacklist AS blacklist, PM.blacklist_remark AS blacklist_remark, PM.blacklist_adate AS blacklist_adate, MA.m_app_id AS app_id, MA.full_name AS replace_name, MA.ldate, MA.service_type AS svc_type, ROW_NUMBER() OVER (PARTITION BY PM.id ORDER BY MA.ldate DESC) AS rn FROM whatever_db.tw_person_merchant PM LEFT JOIN ( whatever_db.tw_person_merchant PMM INNER JOIN whatever_db.tw_merchant_application_details MA ON PMM.app_id = MA.m_app_id INNER JOIN whatever_db.tw_merchant_application MAP ON MA.m_app_id = MAP.id AND MAP.status NOT IN ('10' , '60') WHERE MA.id = (SELECT max(id) FROM whatever_db.tw_merchant_application_details WHERE m_app_id = PMM.app_id ) ) ON PM.app_id = MA.m_app_id WHERE PM.details_status IN ('90', '0') AND PM.blacklist = 0 AND PM.name != '' ) t WHERE rn = 1 ORDER BY id DESC;
内容的提问来源于stack exchange,提问作者dumb
相关产品推荐
相关产品推荐

