You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python读取JSON解析后操作SQL Server数据库报错排查

报错根因
  1. 遍历逻辑完全错误:json.load(f)返回的是顶层字典对象,直接for entry in data遍历字典时,拿到的entry是字典的顶层键名(即"class"、"data"这类字符串),字符串类型没有get()方法,直接触发报错。
  2. 其余代码存在多处逻辑错误,完全无法实现需求:
    • 数据库连接字符串拼接错误:密码参数后漏了分号,同时配置账号密码和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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 22:54:25