我试图通过使用PYODBCpython包的SQL合并语句从JSON文件传递值.以下是JSON文件的示例,其中包含2023年美元对162个国家/地区的汇率数据:

{"2023-01-01": {"USD": 1, "AED": 3.6725, "AFN": 88.74103815},
 "2023-01-02": {"USD": 1, "AED": 3.6725, "AFN": 89.02144276}}

我使用以下代码将其解压缩为我的Python to SQL合并作业(job)所使用的格式(列表列表):

with open('ExchangeRates.json', 'r') as f:
    data = json.load(f)
result = []
for date, conversion_rates in data.items():
    for currency, rate in conversion_rates.items():
        result.append(['USD', currency, rate, parser.parse(date)])

以下是结果样本:

[['USD', 'XOF', 593.76331894, '2023-12-30'], ['USD', 'XPF', 108.01769686, '2023-12-30'],
 ['USD', 'YER', 247.14186482, '2023-12-30'], ['USD', 'ZAR', 18.35621464, '2023-12-30'],
 ['USD', 'ZMW', 25.69324612, '2023-12-30'], ['USD', 'ZWL', 6047.08996546, '2023-12-30']]

我要传递给pyodbc cursor.execute()的SQL和参数参数:

sql = """
MERGE INTO database.dbo.table_name AS Target
USING (
    VALUES {}
) AS Source (currency_from, currency_to, factor, timestamp)
ON Target.currency_from = Source.currency_from 
AND Target.currency_to = Source.currency_to
AND CAST(Target.timestamp as date) = CAST(Source.timestamp as date)
WHEN NOT MATCHED THEN
    INSERT (currency_from, currency_to, factor, timestamp) VALUES (Source.currency_from, Source.currency_to, Source.factor, Source.timestamp);
""".format(','.join(['(?,?,?,?)' for _ in range(len(data))]))

params = [item for sublist in data for item in sublist]

cnxn = pyodbc.connect(conn_string)
crsr = cnxn.cursor()

try:
    crsr.execute(sql, params)
except Exception as e:
    crsr.rollback()
    print(e)
    print('Transaction rollback')
else:
    cnxn.commit()
    crsr.close()
    cnxn.close()

这个代码在过go 是有效的,一切似乎都是正确的.我通过打印它们的输出分别判断了每个部分,我发现SQL代码字符串上的格式联接操作插入(?,?)58,968次(162个国家*364天),并且PARAMS变量将每个列值分离到一个由235,872个元素(58,968行*4列)组成的长列表中,这看起来都是正确的.我判断了我的工作查询,它们传递给cursor.execute(sql, params)个相同的东西,只是数据要少得多.

我每天做的巨 Python 工作,连接到一个网站,让当天的美元对162个其他国家的汇率完美地工作.我能想到的唯一一件事是,我向pyodbc游标执行函数传递了太多数据.请帮我弄清楚为什么pyodbc/sql认为我提供了"-26272个参数标记",以及如何纠正我的编码错误.

推荐答案

正如Alway sLearning所说,VALUES一次只接受VALUES0行.这意味着我收到了错误,因为我输入的行数是最大行数的VALUES 58倍.

我使用的解决方案是以250行为一批进行合并(因为误读了注释,以为只能插入1000个元素,而不是1000行).以下代码替换了旧的SQL合并节:

batch_size = 250
batches = [data[i:i + batch_size] for i in range(0, len(data), batch_size)]

# Prepare SQL template
sql_template = """
MERGE INTO database.dbo.table_name AS Target
USING (
    VALUES {}
) AS Source (currency_from, currency_to, factor, timestamp)
ON Target.currency_from = Source.currency_from 
AND Target.currency_to = Source.currency_to
AND CAST(Target.timestamp as date) = CAST(Source.timestamp as date)
WHEN NOT MATCHED THEN
    INSERT (currency_from, currency_to, factor, timestamp) VALUES (Source.currency_from, Source.currency_to, Source.factor, Source.timestamp);
"""

# Execute batches
cnxn = pyodbc.connect(conn_string)
crsr = cnxn.cursor()

try:
    for batch in batches:
        # Create a comma-separated list of placeholders for each batch
        placeholders = ','.join(['(?,?,?,?)'] * len(batch))
        sql = sql_template.format(placeholders)
        params = [item for sublist in batch for item in sublist]
        crsr.execute(sql, params)
        cnxn.commit()
except Exception as e:
    crsr.rollback()
    print(e)
    print('Transaction rollback')
finally:
    crsr.close()
    cnxn.close()

Python相关问答推荐

Pandas 滚动最接近的价值

ModuleNotFound错误:没有名为flags.State的模块; flags不是包

为什么以这种方式调用pd.ExcelWriter会创建无效的文件格式或扩展名?

如何在Raspberry Pi上检测USB并使用Python访问它?

如何创建一个缓冲区周围的一行与manim?

在pandas中使用group_by,但有条件

改进大型数据集的框架性能

Python脚本使用蓝牙运行在Windows 11与raspberry pi4

启用/禁用shiny 的自动重新加载

解决调用嵌入式函数的XSLT中表达式的语法移位/归约冲突

使用BeautifulSoup抓取所有链接

Pandas:填充行并删除重复项,但保留不同的值

polars:有效的方法来应用函数过滤列的字符串

在numpy数组中寻找楼梯状 struct

从嵌套极轴列的列表中删除元素

每次查询的流通股数量

SpaCy:Regex模式在基于规则的匹配器中不起作用

如何从一个维基页面中抓取和存储多个表格?

如何在不不断遇到ChromeDriver版本错误的情况下使用Selify?

将索引表转换为Numy数组