Python遍历字典按字段类型拼接SQL的循环逻辑问题
按字段类型动态拼接MERGE SQL的实现方案
问题背景
- 首先通过如下代码获取表结构字段字典,字典键为字段名,值为字段类型:
try: columns = get_table_columns(table, cursor) print(columns) except Exception as e: # 原有异常处理逻辑 pass
- 字典结构示例:
{'EFF_DT': 'DATE', 'TERM_DT': 'DATE', 'PACKAGE_LABEL': 'TEXT'}
- 需求规则:拼接MERGE语句时,所有类型为
DATE的字段(包含主键字段),需要对临时表侧的字段值包裹TO_DATE(..., 'DD/MM/YYYY')做日期转换,非DATE类型字段直接按原逻辑拼接。 - 原有代码已经实现了UPDATE分支、INSERT分支的DATE类型字段处理,但主键关联(ON子句)部分未做类型适配,直接嵌套循环判断会产生冗余遍历,导致SQL语法错误。原有问题代码如下:
for key in primary_keys: sql += '{table}."{key}" = {temp_table}."{key}"'.format( table=table, temp_table=temp_table, key=key ) if key == primary_keys[-1]: continue sql += " and " sql += " WHEN MATCHED THEN update set " for column in columns: if columns[column]=="DATE": sql+="{table}.\"{column}\" = TO_DATE({temp_table}.\"{column}\", 'DD/MM/YYYY'), ".format(table=table, temp_table=temp_table, column=column) continue sql+= "{table}.\"{column}\" = {temp_table}.\"{column}\", ".format(table=table, temp_table=temp_table, column=column) sql = sql[:-2] sql+= " when not matched then insert values ( " for column in columns: if columns[column]=="DATE": sql+="TO_DATE("+table+"_TEMP.\""+column+"\", 'DD/MM/YYYY')" else: sql+= table+"_TEMP.\""+column+"\"" if column ==list(columns.keys())[-1]: sql += " );" continue sql+=", "
优化实现方案
核心思路:不需要嵌套循环,遍历主键时直接从已有的columns字典中查询当前主键的类型即可,字典键查询时间复杂度为O(1),无冗余遍历问题。同时抽离公共字段转换逻辑,替换手动拼接逗号的易出错写法。
优化后完整代码
# 抽离公共字段表达式生成逻辑,三处拼接场景复用,避免重复写判断 def gen_field_expr(table_alias: str, col_name: str, col_type_map: dict) -> str: col_type = col_type_map.get(col_name) if col_type == "DATE": # DATE类型对临时表侧字段做TO_DATE转换 return f"TO_DATE({table_alias}.\"{col_name}\", 'DD/MM/YYYY')" # 非DATE类型直接返回字段引用 return f"{table_alias}.\"{col_name}\"" # 1. 拼接ON子句主键关联条件 on_clauses = [] for pk in primary_keys: # 主表字段本身是结构化存储的DATE类型,不需要转换 left_expr = f'{table}."{pk}"' # 临时表字段按类型规则生成表达式 right_expr = gen_field_expr(temp_table, pk, columns) on_clauses.append(f"{left_expr} = {right_expr}") sql += " AND ".join(on_clauses) # 2. 拼接MATCHED时的UPDATE分支 sql += " WHEN MATCHED THEN UPDATE SET " update_clauses = [] for col in columns: left_expr = f'{table}."{col}"' right_expr = gen_field_expr(temp_table, col, columns) update_clauses.append(f"{left_expr} = {right_expr}") sql += ", ".join(update_clauses) # 3. 拼接NOT MATCHED时的INSERT分支 sql += " WHEN NOT MATCHED THEN INSERT VALUES ( " insert_value_exprs = [] for col in columns: insert_value_exprs.append(gen_field_expr(f"{table}_TEMP", col, columns)) sql += ", ".join(insert_value_exprs) sql += ");"
方案优势
- 无冗余循环:主键遍历过程直接通过字典查询字段类型,不存在嵌套遍历的性能问题和逻辑错误
- 易维护:字段类型转换逻辑统一收敛在
gen_field_expr函数中,后续如果需要新增TIMESTAMP、数值格式化等其他类型处理,只需要修改这一处代码即可 - 语法更稳定:替换了原代码中通过
sql[:-2]截断末尾逗号的写法,改用列表收集SQL片段后通过join拼接分隔符,从根源避免多余逗号、漏拼分隔符导致的SQL语法错误
内容的提问来源于stack exchange,提问作者titan31
相关产品推荐
相关产品推荐

