PyMySql执行MAX(timestamp)查询出现'0000-00-00 00:00:00'错误警告
我在MySQL 5.7上有两张表:
- Table_A:字段是
id和name,数据是1 foo、2 bar - Table_B:字段包括
id、parent_id、name和created_at(created_at默认值设为CURRENT_TIMESTAMP),现有数据是1 1 x 2019-01-01 10:00:00、2 1 y 2019-12-31 22:00:00
我写了个分组查询,想按Table_A的名称统计对应的Table_B条目数,以及最新条目的时间戳:
SELECT a.name, COUNT(b.id) AS entry_count_in_b, MAX(b.created_at) AS last_entry_in_b FROM Table_A a LEFT JOIN Table_B b ON b.parent_id = a.id GROUP BY 1
在MySQL命令行里跑这个查询完全正常,结果符合预期。但用Python 3.7搭配PyMySQL 0.9.3执行时,游标却弹出警告说行3的last_entry_in_b列有无效时间值0000-00-00 00:00:00——可实际返回的结果明明只有2行(和Table_A的数据量一致,是对的)。
后来我试着用CASE语句处理NULL的情况,改成了这样:
SELECT a.name, COUNT(b.id) AS entry_count_in_b, CASE WHEN MAX(b.created_at) IS NOT NULL THEN MAX(b.created_at) ELSE NULL END AS last_entry_in_b FROM Table_A a LEFT JOIN Table_B b ON b.parent_id = a.id GROUP BY 1
结果警告还是出现,只是把列名换成了tmp_field_0。
我搜了一圈相关问题,发现大多都是插入或更新时遇到0000-00-00 00:00:00的情况,和我这种查询场景不一样。想问问有没有人碰到过这个问题并解决了?要是没有的话,我就去提交PyMySQL的issue了。
这个问题应该是PyMySQL在处理LEFT JOIN后MAX(created_at)返回的NULL值时,内部错误地把它转换成了0000-00-00 00:00:00这个无效时间戳,才触发了警告。这里有几个可行的思路:
1. 把NULL转成合法的时间值
既然PyMySQL对NULL时间处理有问题,那我们直接在查询里把NULL结果换成一个合法的时间就行,比如Unix纪元时间1970-01-01 00:00:00,MySQL默认是允许这个值的:
SELECT a.name, COUNT(b.id) AS entry_count_in_b, COALESCE(MAX(b.created_at), '1970-01-01 00:00:00') AS last_entry_in_b FROM Table_A a LEFT JOIN Table_B b ON b.parent_id = a.id GROUP BY 1
这样返回的所有时间都是合法的,PyMySQL就不会报警告了。之后在Python代码里,你可以根据业务需求把这个值再转成None。
2. 调整PyMySQL连接的SQL模式
创建PyMySQL连接的时候,加上sql_mode参数,关闭对无效时间戳的严格检查:
import pymysql conn = pymysql.connect( host='你的数据库地址', user='用户名', password='密码', db='数据库名', charset='utf8mb4', sql_mode='NO_ZERO_DATE,NO_ZERO_IN_DATE' )
不过这个方法会影响整个连接的SQL模式,得确认会不会和你的其他业务逻辑冲突。
3. 升级PyMySQL版本
你现在用的PyMySQL 0.9.3是2019年的老版本了,这个问题说不定在后续版本里已经被修复了。建议先试试升级到最新稳定版:
pip install --upgrade pymysql
升级完再跑查询,看看警告会不会消失。
内容的提问来源于stack exchange,提问作者Stipy

