MySQL查询返回None问题排查:获取近7天数据失败
问题描述
我正在编写一个从SQL数据库中获取近7天数据的函数,但遇到了问题。函数代码如下:
def get_last_7_days(mycursor): current_date = dt.now().date() date_minus_7 = dt.today() - td(days=7) dates = pd.date_range(date_minus_7.date(), current_date) for date in dates: row = mycursor.execute(f"SELECT * FROM work_times WHERE date = {date.date()}") print(row)
问题在于,即便列名正确且数据库中存在匹配日期的记录,execute语句仍返回None。
查询的表结构及数据如下:
+------------+------------+----------+--------------+------+ | date | start_time | end_time | hours_worked | pay | +------------+------------+----------+--------------+------+ | 2023-08-09 | 07:00:00 | 14:30:00 | 7 | 81 | | 2023-08-08 | 14:30:00 | 22:00:00 | 7 | 81 | | 2023-08-07 | 07:00:00 | 14:30:00 | 7 | 81 | | 2023-08-06 | 14:00:00 | 22:00:00 | 8 | 89 | +------------+------------+----------+--------------+------+
我尝试了多种方法:将date转为字符串、给date.date()加引号、使用execute占位符(%s)、子查询日期范围、列名加反引号等,但均未解决。不过在终端执行SELECT * FROM work_times WHERE date = '2023-08-09';能正常返回结果。我打算先转成DataFrame用Pandas查询,但想先了解该语句失效的原因,恳请各位帮忙解答。
问题原因与解决方法
1. execute方法本身不返回查询结果
不管SQL查询是否命中数据,mycursor.execute()执行后默认返回None,你需要调用游标对应的方法来获取实际查询结果,比如:
mycursor.fetchone():获取单条记录mycursor.fetchall():获取所有匹配记录mycursor.fetchmany(n):获取指定数量的记录
你之前的代码里,row变量接收的是execute的返回值,自然是None,这和SQL语句是否正确无关。
2. SQL语句的语法问题(字符串拼接导致日期格式错误)
用f-string拼接{date.date()}时,生成的SQL语句是SELECT * FROM work_times WHERE date = 2023-08-09,这在SQL中会被解析为数学运算(2023减8减9),而非日期字符串,导致查询匹配失败。
正确的做法是使用参数化查询(占位符),既避免SQL注入风险,又能保证日期格式正确:
def get_last_7_days(mycursor): current_date = dt.now().date() date_minus_7 = dt.today() - td(days=7) dates = pd.date_range(date_minus_7.date(), current_date) for date in dates: mycursor.execute("SELECT * FROM work_times WHERE date = %s", (date.date(),)) row = mycursor.fetchone() # 或根据需求用fetchall() print(row)
3. 优化建议:一次查询替代循环遍历日期
没必要循环每个日期单独查询,直接用日期范围查询可减少数据库交互次数,效率更高:
def get_last_7_days(mycursor): current_date = dt.now().date() date_minus_7 = dt.today() - td(days=7) mycursor.execute("SELECT * FROM work_times WHERE date BETWEEN %s AND %s", (date_minus_7.date(), current_date)) all_rows = mycursor.fetchall() for row in all_rows: print(row)
如果用Pandas处理,直接用pd.read_sql会更便捷:
import pandas as pd def get_last_7_days_pandas(conn): current_date = dt.now().date() date_minus_7 = dt.today() - td(days=7) query = "SELECT * FROM work_times WHERE date BETWEEN %s AND %s" df = pd.read_sql(query, conn, params=(date_minus_7.date(), current_date)) print(df)
内容的提问来源于stack exchange,提问作者Goon-Bug
相关产品推荐
相关产品推荐

