Python读取JSON解析后操作SQL Server数据库报错排查
报错根因
- 遍历逻辑完全错误:
json.load(f)返回的是顶层字典对象,直接for entry in data遍历字典时,拿到的entry是字典的顶层键名(即"class"、"data"这类字符串),字符串类型没有get()方法,直接触发报错。 - 其余代码存在多处逻辑错误,完全无法实现需求:
- 数据库连接字符串拼接错误:密码参数后漏了分号,同时配置账号密码和Windows信任认证会导致连接冲突
- INSERT语句占位符仅写了4个,和实际要插入的字段(时间、文件名、data下的十余个业务字段)数量完全不匹配
- 取值范围错误:业务字段都在
data键对应的子字典内,没有读取该子字典就直接取值 - keys列表重复定义了
container字段,会导致取值重复、列数错位 - 未实现
class字段判断逻辑,既没有write分支的写入适配,也没有delete分支的删除逻辑 locks字段是数组结构,无法直接写入SQL Server普通列,需要序列化处理- 冗余写了
f.close():with open上下文管理器会自动关闭文件,不需要手动调用 - 每个JSON文件新建一次数据库连接,性能差且容易出现连接泄漏
修正后实现代码
import os import json import pyodbc from datetime import datetime # 配置参数 destination_dir = "你的JSON文件目录路径" server = 'mainserver' db = 'MainDataBase' UID = 'userName' PWD = 'password' table_name = '你的实际数据库表名' # 业务字段列表,去掉重复的container biz_keys = [ "booking", "driversLicense", "container", "driversId", "excessA", "excessB", "excessC", "excessD", "excessE", "locks", "mission", "foreignDrive", "nameDrive", "numberSav", "weight", "truck", "dolly", "type" ] # 初始化数据库连接(循环外创建,复用连接) conn = pyodbc.connect( f'DRIVER={{SQL Server}};SERVER={server};DATABASE={db};UID={UID};PWD={PWD}' ) cursor = conn.cursor() try: for filename in os.listdir(destination_dir): if not filename.endswith('.json'): continue file_path = os.path.join(destination_dir, filename) # 读取并解析JSON with open(file_path, 'r', encoding='utf-8') as f: file_data = json.load(f) op_type = file_data.get('class') biz_data = file_data.get('data', {}) # 没有data字段的坏文件直接跳过 if not biz_data: print(f"文件{filename}无有效data字段,跳过") continue if op_type == 'write': # 组装插入值:当前时间、文件名、各业务字段值 insert_values = [datetime.now(), filename] for key in biz_keys: val = biz_data.get(key, None) # 数组/对象类型序列化为JSON字符串存储 if isinstance(val, (list, dict)): val = json.dumps(val, ensure_ascii=False) insert_values.append(val) # 生成对应数量的占位符 placeholders = ','.join(['?'] * len(insert_values)) # 写清楚插入的字段名,避免表结构变动导致错位 insert_sql = f""" INSERT INTO {table_name} ( create_datetime, file_name, booking, driversLicense, container, driversId, excessA, excessB, excessC, excessD, excessE, locks, mission, foreignDrive, nameDrive, numberSav, weight, truck, dolly, type ) VALUES ({placeholders}) """ cursor.execute(insert_sql, insert_values) conn.commit() print(f"文件{filename}写入完成") elif op_type == 'delete': # 以numberSav作为唯一匹配标识删除,根据业务实际可替换为其他唯一键 target_number = biz_data.get('numberSav') if not target_number: print(f"文件{filename}delete操作无有效numberSav,跳过") continue delete_sql = f"DELETE FROM {table_name} WHERE numberSav = ?" cursor.execute(delete_sql, (target_number,)) conn.commit() print(f"文件{filename}对应编号{target_number}数据删除完成") else: print(f"文件{filename}class字段为{op_type},无对应处理逻辑,跳过") except Exception as e: conn.rollback() print(f"执行出错,已回滚:{str(e)}") finally: cursor.close() conn.close()
适配说明
- 代码里的
destination_dir、table_name替换成你实际的路径和表名,如果表内时间字段、文件名字段的命名和代码里不一致,对应修改INSERT语句里的字段名即可 - 删除逻辑默认用
numberSav作为数据唯一匹配标识,如果你的业务用其他字段做唯一键,直接替换DELETE语句里的匹配条件即可 - 如果你的
class字段写入/删除对应的取值不是write/delete(比如示例里的savSend对应写入),直接修改判断分支的字符串匹配规则 locks这类复杂结构字段统一序列化为JSON字符串存储,如果你的SQL Server版本支持JSON类型列可以直接存,不支持的话用NVARCHAR(MAX)类型字段即可
内容的提问来源于stack exchange,提问作者SanctaMariaMaterDeiOraProNobis
相关产品推荐
相关产品推荐

