MySQL查询返回0结果问题排查(涉及CONCAT与CAST函数)
排查MySQL查询返回0结果的问题
让我从语法和逻辑两方面帮你分析这个问题:
首先是语法错误
MySQL里用CAST()转换为字符串类型时,正确的类型关键字是CHAR,而不是你写的VARCHAR。你的代码里CAST(r.any - 1 as varchar(4))不符合MySQL语法规范,应该改成CAST(r.any - 1 AS CHAR(4))(或者简化成CAST(r.any -1 AS CHAR))。虽然部分MySQL版本可能会兼容这个错误,但这是第一个需要修正的点,否则可能导致条件判断异常。
核心问题:逻辑冲突导致无匹配行
你添加的那段代码和原有的p.any_id条件存在逻辑冲突,这才是查询返回0结果的关键原因:
原有的p.any_id固定限制
(p.any_id = '2017-2018' or p.any_id = '2016-2017')
这把p.any_id的取值范围固定在了两个特定字符串上。
新添加的动态匹配条件
((r.mes < 9 and p.any_id = CONCAT(CAST(r.any - 1 as CHAR(4)),"-",CAST(r.any as CHAR(4)))) or (r.mes >= 9 and p.any_id = CONCAT(CAST(r.any as CHAR(4)),"-",CAST(r.any + 1 as CHAR(4)))))
我们拆解这个逻辑:
- 当
r.mes <9时,动态生成的p.any_id格式是(年份-1)-年份,比如2017年的话就是2016-2017,2018年的话是2017-2018 - 当
r.mes >=9时,动态生成的格式是年份-(年份+1),比如2017年是2017-2018,2018年是2018-2019
同时,你原有的时间范围条件还藏着冗余无效的逻辑:
((r.any = 2017 and r.mes = 1) or (r.any > 2017 and r.any < 2018) or (r.any = 2018 and r.mes = 1) or (2017 != 2018 and ((r.any = 2017 and r.mes > 1) or (r.any = 2018 and r.mes < 1))))
r.any >2017 and r.any <2018永远为假,因为年份是整数,不存在中间值r.any=2018 and r.mes <1也永远为假,月份的最小值是1
简化后有效的时间范围其实是:2017全年 + 2018年1月,也就是(r.any =2017) OR (r.any=2018 AND r.mes=1)。
结合起来看:只有当动态生成的p.any_id恰好等于2016-2017或2017-2018时,才会有匹配的行。如果你的数据里没有同时满足这些交叉条件的记录,就会返回0结果。
修复建议
- 修正CAST语法:把所有
varchar(4)改成CHAR(4) - 简化时间条件:替换冗余的时间判断,让逻辑更清晰
- 验证条件交集:先单独查询看看有没有行同时满足
p.any_id的固定值和动态生成值,比如执行下面的测试语句:
SELECT r.any, r.mes, CONCAT(CAST(r.any -1 AS CHAR(4)),"-",CAST(r.any AS CHAR(4))) as expected_id1, CONCAT(CAST(r.any AS CHAR(4)),"-",CAST(r.any +1 AS CHAR(4))) as expected_id2, p.any_id FROM report r JOIN persona p ON r.usuari_upc = p.persona_id WHERE (r.any = 2017 OR (r.any =2018 AND r.mes=1)) AND (p.any_id = '2017-2018' OR p.any_id = '2016-2017')
如果查询结果里没有p.any_id等于expected_id1或expected_id2的行,说明这两组条件确实没有交集,需要根据你的业务需求调整:要么放宽p.any_id的固定值限制,要么修改动态匹配的逻辑。
最后附上修正语法和简化后的完整查询示例:
SELECT p.seccio_id as seccio, COUNT(DISTINCT r.usuari_upc) as usuaris, SUM(r.preu) as preu FROM report r JOIN persona p ON r.usuari_upc = p.persona_id WHERE -- 简化后的有效时间范围 (r.any = 2017 OR (r.any = 2018 AND r.mes = 1)) AND (p.any_id = '2017-2018' OR p.any_id = '2016-2017') AND ( (r.mes < 9 AND p.any_id = CONCAT(CAST(r.any - 1 AS CHAR(4)),"-",CAST(r.any AS CHAR(4)))) OR (r.mes >= 9 AND p.any_id = CONCAT(CAST(r.any AS CHAR(4)),"-",CAST(r.any + 1 AS CHAR(4)))) ) GROUP BY p.seccio_id ORDER BY p.seccio_id
内容的提问来源于stack exchange,提问作者Manelicus
相关产品推荐
相关产品推荐

