MySQL多列条件下更新指定日期范围数据误更新问题
问题原因
你写的更新语句存在3个核心问题,是导致误更新的根本原因:
- 字段名错误加了单引号:
SET '%s'会把传入的字段名识别为字符串,语法本身不符合SQL规范,你要更新的req字段不需要套单引号,仅当字段名是数据库保留字时才需要加反引号包裹。 - 日期范围判断逻辑缺失:你只加了
month BETWEEN 起始月 AND 结束月的条件,完全没有对day字段做边界限制,既没有过滤起始月早于起始日的行,也没有过滤结束月晚于结束日的行,自然会把6月1-6日、9月17日之后同月份、同星期值的行错误更新。如果传入的year参数不对,还会误改其他年份同月份的数据。 - 字符串拼接SQL的写法风险高:直接用%拼接SQL不仅容易出现引号转义错误,还存在SQL注入隐患,参数值的类型匹配也容易出问题。
正确实现方案
要严格限定日期区间,需要把日期边界拆成三段判断,覆盖起始月、中间整月、结束月三种场景,不要只判断月份范围:
- 年份必须匹配目标年份
- 月份、日期满足以下任意一种情况:
- 是起始月,且日期大于等于起始日
- 月份在起始月和结束月之间(即不包含首尾的中间月份,整月生效)
- 是结束月,且日期小于等于结束日
- 最后匹配要求的
dow字段值
推荐用参数化查询的方式写代码,避免拼接错误:
# 配置目标参数 target_year = 2022 start_month = 6 start_day = 7 end_month = 9 end_day = 16 target_dow = "mon" # 替换为你需要匹配的星期值 update_val = 9 query = """ UPDATE calendar SET req = %s WHERE year = %s AND ( (month = %s AND day >= %s) OR (month > %s AND month < %s) OR (month = %s AND day <= %s) ) AND dow = %s """ # 参数按顺序传入,不要直接拼接到SQL字符串中 query_params = (update_val, target_year, start_month, start_day, start_month, end_month, end_month, end_day, target_dow) Functions.handleQuery(self, query, query_params)
如果使用的数据库支持日期函数,也可以直接把三个字段拼接为标准日期做区间判断,逻辑更直观不容易写错边界,以MySQL为例可以把日期判断部分替换为:
STR_TO_DATE(CONCAT(year, '-', month, '-', day), '%Y-%c-%e') BETWEEN '2022-06-07' AND '2022-09-16'
内容的提问来源于stack exchange,提问作者user17565490
相关产品推荐
相关产品推荐

