解决Tkinter日历get_date()日期与Oracle datetime字段匹配查询的报错问题
解决Tkinter日历get_date()日期与Oracle datetime字段匹配查询的报错问题
嘿,我看你被Tkinter日历日期和Oracle datetime字段的查询报错给难住了,咱们一步步把这个问题解决掉!
先说说你当前代码里的几个核心问题:
- 直接拼接字符串到SQL的坑:你把转换后的日期字符串直接拼进SQL语句,不仅容易因为Oracle的会话日期格式设置不同触发
ORA-01861格式不匹配错误,还存在严重的SQL注入风险,这在生产环境里绝对是要避免的。 - 日期转换的冗余操作:你把日历获取的日期转成带时分秒的字符串,但其实完全没必要手动做这个转换,Python的日期对象可以直接通过参数绑定传给Oracle驱动,驱动会自动处理格式匹配。
- 之前的TypeError根源:最开始你直接用
get_date()返回的Timestamp或datetime.date对象拼接字符串,Python自然会报错“不能把字符串和日期对象拼接”,后来你转成了字符串,但还是没解决根本的格式和安全问题。
下面给你两种解决方式,优先推荐第一种:
方式一:用参数绑定直接传Python日期对象(最推荐)
这种方式彻底规避格式问题和SQL注入,代码也更简洁:
from datetime import datetime # 获取日历的日期,假设get_date()返回的是datetime.date对象 Fecha = self.cal1.get_date() # 把date对象转成datetime对象(时分秒设为0,匹配Oracle的datetime字段) fecha_dt = datetime.combine(Fecha, datetime.min.time()) # 写SQL的时候用占位符(Oracle用:1这种位置占位符,或者命名占位符都可以) sql = """ SELECT t3.DESCRIPTION as ASSET_DESCRIPTION FROM maximo.BTV_workorder T1 INNER JOIN maximo.BTV_PM t2 ON t2.Assetnum=T1.Assetnum LEFT JOIN maximo.BTV_ASSET t3 ON T1.ASSETNUM=t3.ASSETNUM WHERE T1.istask='1' AND T1.SITEID='ALBAL' AND T1.STATUS='COMP' AND t2.STATUS='ACTIVE' AND t1.STATUSDATE = :target_date """ # 执行SQL时传入参数,驱动会自动处理日期格式转换 cursor.execute(sql, [fecha_dt]) # 或者用命名参数更清晰:cursor.execute(sql, target_date=fecha_dt)
为什么推荐这个方法?
- Oracle驱动会自动把Python的datetime对象转换成Oracle能识别的datetime格式,完全不会出现
ORA-01861错误。 - 彻底避免SQL注入,这是生产环境代码的基本要求。
- 不用手动处理字符串拼接,自然不会再出现TypeError。
方式二:用TO_DATE函数指定格式(不推荐,仅作参考)
如果你一定要用字符串转换的方式,那必须用Oracle的TO_DATE函数明确指定日期格式,同时依然用参数绑定(别再直接拼接了!):
Fecha = self.cal1.get_date() # 转成带时分秒的字符串 fecha_str = Fecha.strftime("%Y-%m-%d %H:%M:%S") # 用TO_DATE把字符串转成Oracle日期,同时用占位符传参 sql = """ SELECT t3.DESCRIPTION as ASSET_DESCRIPTION FROM maximo.BTV_workorder T1 INNER JOIN maximo.BTV_PM t2 ON t2.Assetnum=T1.Assetnum LEFT JOIN maximo.BTV_ASSET t3 ON T1.ASSETNUM=t3.ASSETNUM WHERE T1.istask='1' AND T1.SITEID='ALBAL' AND T1.STATUS='COMP' AND t2.STATUS='ACTIVE' AND t1.STATUSDATE = TO_DATE(:target_date_str, 'YYYY-MM-DD HH24:MI:SS') """ # 执行时传入字符串参数 cursor.execute(sql, [fecha_str])
这里要注意,Oracle的时分秒格式用HH24表示24小时制,MI表示分钟,SS表示秒,别写错成MM(那是月份)。
最后再提个小细节
你原来的SQL里用的是t1.STATUSDATE = 'xxx',如果Oracle的STATUSDATE是datetime字段,而你要匹配的是某一天的所有记录(不是精确到秒的时间点),那应该用范围查询,比如:
AND t1.STATUSDATE BETWEEN :start_date AND :end_date
对应的Python代码就是把当天的0点和次日的0点传进去,这样就能查到当天所有状态日期为COMP的工单了。
备注:内容来源于stack exchange,提问作者Monvana
相关产品推荐
相关产品推荐

