MySQL 8存储过程执行报错1172排查及登录天数校验需求实现问题
MySQL 8存储过程执行报错1172排查及登录天数校验需求实现问题
嗨,我来帮你拆解并解决这个问题~ 你遇到的1172 - Result consisted of more than one row错误,核心原因是存储过程里的统计SQL返回了多行结果,但你的变量只能接收单个值,咱们一步步来修正:
一、报错根源分析
原SQL语句里加了GROUP BY DATE(B.tDate),这会把每个登录日期单独分组统计——比如用户在2025-01-02和2025-01-05登录,这条SQL会返回两行,每行的count值都是1。而SELECT ... INTO @n语法要求结果集只能有1行1列,所以直接触发了1172错误。
另外你要的是去重后的登录总天数,根本不需要分组,直接用COUNT(DISTINCT DATE(B.tDate))就能得到正确的数字,完全没必要加GROUP BY。
二、修正后的完整存储过程
我帮你重新写了更简洁、正确的版本,去掉了冗余代码,修复了逻辑问题:
CREATE DEFINER=`root`@`%` PROCEDURE `dCreate_20250723`() BEGIN DECLARE login_days INT; -- 直接统计2025年1月用户foo的去重登录天数,无需动态SQL SELECT COUNT(DISTINCT DATE(tDate)) INTO login_days FROM `dotable_1` WHERE YEAR(tDate) = 2025 AND MONTH(tDate) = 1 AND tUsers = 'foo'; -- 根据统计结果更新校验表 IF login_days >= 2 THEN UPDATE `dotable_2` SET tCheck = 'OK' WHERE tUsers = 'foo'; ELSE UPDATE `dotable_2` SET tCheck = 'KO' WHERE tUsers = 'foo'; END IF; END
三、关键修改点说明
- 移除冗余代码:删掉了无关的
FLUSH HOSTS命令(这个是清理MySQL主机缓存,和你的登录天数统计逻辑完全不相关),也去掉了没必要的动态SQL(你的SQL里没有动态表名/字段,静态SQL更安全易维护)。 - 修复统计逻辑:用
COUNT(DISTINCT DATE(tDate))直接计算去重后的登录日期总数,彻底避免了GROUP BY导致的多行结果问题。 - 简化变量处理:用局部变量
login_days直接接收统计结果,不需要中间的会话变量@n,逻辑更清晰。 - 统一引号格式:把混乱的转义引号统一为MySQL标准的单引号,避免语法歧义。
四、进阶优化建议(可选)
如果以后需要支持动态的年份、月份或者用户名,建议把这些作为存储过程的参数,让存储过程更通用:
CREATE DEFINER=`root`@`%` PROCEDURE `check_user_login_days`( IN p_year INT, IN p_month INT, IN p_username VARCHAR(100) ) BEGIN DECLARE login_days INT; SELECT COUNT(DISTINCT DATE(tDate)) INTO login_days FROM `dotable_1` WHERE YEAR(tDate) = p_year AND MONTH(tDate) = p_month AND tUsers = p_username; IF login_days >= 2 THEN UPDATE `dotable_2` SET tCheck = 'OK' WHERE tUsers = p_username; ELSE UPDATE `dotable_2` SET tCheck = 'KO' WHERE tUsers = p_username; END IF; END
调用的时候就可以指定参数:CALL check_user_login_days(2025, 1, 'foo');
内容来源于stack exchange




