Python使用pymssql查询SQL Server时如何按指定时间间隔从游标取数?
问题产生原因
- 逻辑表达式优先级错误
你写的"07:00" or "19:00" in cursor不会按照你预期的"07:00" in 时间字段 或者 "19:00" in 时间字段执行,实际运算逻辑等价于(bool("07:00")) or ("19:00" in cursor),非空字符串的布尔值恒为True,理论上整个条件应该永远为True,你遇到条件始终返回False的核心原因是第二个错误。 - 匹配对象错误
你判断的是in cursor而不是当前遍历行的时间字段i[0],cursor是游标迭代器,执行in操作会直接耗尽整个迭代器的所有数据,第一次判断完成后游标已经没有剩余数据可以遍历,最终拿到的结果自然是空。 - 效率缺陷
即便你修正了Python层面的过滤逻辑,先把4万多条全量数据拉到本地再过滤的方案也会浪费大量数据库IO、网络传输和本地内存资源,属于非常低效的实现。
最优解决方案:修改SQL查询语句
直接在SQL查询层面做过滤是性能最好的方案,数据库可以利用时间字段的索引直接返回符合条件的数据,不需要拉取全量内容。
针对SQL Server的查询写法示例:
-- 假设表名为sensor_data,时间字段为dt,数值字段为val SELECT dt, val FROM sensor_data WHERE -- 按需求修改目标小时,6小时间隔取4次可填(1,7,13,19) DATEPART(HOUR, dt) IN (7, 19) -- 如果只需要整点的第一条数据,可加下面的条件 AND DATEPART(MINUTE, dt) = 0 -- 可自行补充查询的时间范围等其他过滤条件 AND dt >= '2021-12-01' AND dt < '2021-12-31'
如果每个整点存在多条传感器数据,需要每天每个目标小时仅返回1条,可以用窗口函数实现:
WITH ranked_sensor AS ( SELECT dt, val, ROW_NUMBER() OVER ( PARTITION BY CAST(dt AS DATE), DATEPART(HOUR, dt) ORDER BY dt ASC ) AS rn FROM sensor_data WHERE DATEPART(HOUR, dt) IN (7, 19) ) SELECT dt, val FROM ranked_sensor WHERE rn = 1
Python层面过滤的修正写法(不推荐)
如果确实无法修改SQL查询,可以用以下正确的写法实现本地过滤:
from datetime import datetime # 写法1:字符串匹配,仅适用于时间字段返回固定格式字符串的场景 res = [i for i in cursor if "07:00:00" in i[0] or "19:00:00" in i[0]] # 写法2:转datetime对象判断,兼容性更高,避免字符串格式变动导致匹配失败 res = [] for dt_str, val in cursor: dt = datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S.%f") # 按需求修改目标小时 if dt.hour in (7, 19) and dt.minute == 0: res.append((dt_str, val))
内容的提问来源于stack exchange,提问作者XYZ123
相关产品推荐
相关产品推荐

