SQL语句使用ROW_NUMBER()本地运行正常但线上MySQL服务器报错如何解决
问题原因
- MySQL版本不兼容窗口函数:
ROW_NUMBER() OVER ()属于窗口函数特性,仅在MySQL 8.0及以上版本支持。如果本地环境使用8.0+版本,而线上服务器使用5.7及更低版本,就会触发1064语法错误,错误位置刚好匹配OVER子句附近,和你收到的报错完全吻合。 - 字段引用错误:PARTITION BY子句中用到的
created_date不存在,原表仅包含created_at字段,你在SELECT层为DATE(created_at)设置的别名是cre_date,存在拼写错误。另外SQL执行优先级中窗口函数早于SELECT层别名生效,即使别名拼写正确,也无法在窗口函数中直接引用,必须直接基于原字段计算。
你提到的静态分析报出的别名重复、缺少别名等错误,都是上述两个核心问题衍生的误报,解决核心问题后会自动消失。
修复方案
方案1:线上可升级到MySQL 8.0+的情况
直接修正字段引用即可,修复后的SQL如下:
SELECT id, user_id, total_usage, DATE(created_at) as cre_date, DATE_FORMAT(DATE(created_at), '%M %Y') as month_year, ROW_NUMBER() OVER (PARTITION BY YEAR(created_at), MONTH(created_at) ORDER BY id DESC) as row_rank FROM daily_usage WHERE user_id = 1
方案2:线上版本无法升级,兼容MySQL 5.x的情况
使用用户变量模拟窗口函数的行号计算逻辑,写法如下:
SELECT id, user_id, total_usage, cre_date, month_year, row_rank FROM ( SELECT id, user_id, total_usage, DATE(created_at) as cre_date, DATE_FORMAT(DATE(created_at), '%M %Y') as month_year, @row_rank := IF(@current_month = DATE_FORMAT(created_at, '%Y%m'), @row_rank + 1, 1) AS row_rank, @current_month := DATE_FORMAT(created_at, '%Y%m') FROM daily_usage WHERE user_id = 1 ORDER BY DATE_FORMAT(created_at, '%Y%m'), id DESC ) AS t, (SELECT @row_rank := 0, @current_month := '') AS init
内容的提问来源于stack exchange,提问作者Gulammustufa Momin
相关产品推荐
相关产品推荐

