Python 基本pyodbc批量插入

Python 基本pyodbc批量插入,python,sql-server,pyodbc,Python,Sql Server,Pyodbc,在python脚本中,我需要在一个数据源上运行一个查询,并将该查询中的每一行插入到另一个数据源上的表中。我通常会使用一个带有tsql链接服务器连接的insert/select语句来实现这一点,但我没有到这个特定数据源的链接服务器连接 我很难找到一个简单的pyodbc示例。下面是我应该怎么做的,但我猜在循环中执行insert语句相当慢 result = ds1Cursor.execute(selectSql) for row in result: insertSql = "insert

在python脚本中,我需要在一个数据源上运行一个查询,并将该查询中的每一行插入到另一个数据源上的表中。我通常会使用一个带有tsql链接服务器连接的insert/select语句来实现这一点,但我没有到这个特定数据源的链接服务器连接

我很难找到一个简单的pyodbc示例。下面是我应该怎么做的,但我猜在循环中执行insert语句相当慢

result = ds1Cursor.execute(selectSql)

for row in result:
    insertSql = "insert into TableName (Col1, Col2, Col3) values (?, ?, ?)"
    ds2Cursor.execute(insertSql, row[0], row[1], row[2])
    ds2Cursor.commit()

使用pyodbc插入记录有更好的批量方式吗?或者这是一种相对有效的方法。我正在使用SQLServer2012以及最新的pyodbc和python版本。

处理此问题的最佳方法是使用pyodbc函数ExecuteMy


这里有一个函数,可以批量插入SQL Server数据库

import pyodbc
import contextlib

def bulk_insert(table_name, file_path):
    string = "BULK INSERT {} FROM '{}' (WITH FORMAT = 'CSV');"
    with contextlib.closing(pyodbc.connect("MYCONN")) as conn:
        with contextlib.closing(conn.cursor()) as cursor:
            cursor.execute(string.format(table_name, file_path))
        conn.commit()
这绝对有效

更新:我注意到在评论和定期编码中,pyodbc比pyodbc更受支持


新更新:删除conn.close,因为with语句会自动处理它。

自从pymssql库停止使用以来,我们开始使用由Zillow的smart people开发的,出乎意料的是,它支持FreeTDS批量插入

顾名思义,cTDS是在库的顶部用C编写的,这使得它非常快。IMHO这是批量插入SQL Server的最佳方式,因为ODBC驱动程序不支持批量插入,而建议的executemany或fast_executemany并不是真正的批量插入操作。BCP工具和T-SQL批量插入有其局限性,因为它需要SQL Server能够访问该文件,而SQL Server在许多情况下都可能是交易破坏者

下面是批量插入CSV文件的简单实现。请原谅我的任何错误,我没有经过测试就写了这篇文章

我不知道为什么,但对于我的服务器,它使用拉丁语1_General_CI_,因为我需要用ctds.SqlVarChar包装进入NVarChar列的数据,所以我改变了密码以保持心理健康

导入csv 进口CTD def_to_varchartxt:str->ctds.VARCHAR: 将字符串包装到ctds.NVARCHAR中。 如果txt==null: 一无所获 返回ctds.SqlNVarChartxt def_to_nvarchartext:str->ctds.VARCHAR: 将字符串包装到ctds.VARCHAR中。 如果txt==null: 一无所获 返回ctds.SqlVarChartxt.encodeutf-16le def读取文件: 打开CSV文件。 每行是一列:value dict。 https://docs.python.org/3/library/csv.html?highlight=csvcsv.DictReader 对于openfile,换行符=作为csvfile: reader=csv.dictReadercsv文件 对于读取器中的行: 产量行 def transformrow: 在加载之前对数据进行转换。 为批量插入文本列而指定的数据,例如VARCHAR, NVARCHAR,文本不会以任何方式由FreeTDS在客户端进行编码。 由于这种行为,可以使用插入文本数据 无效编码并导致列数据损坏。 为了防止出现这种情况,建议调用者显式地包装 具有ctds.SqlVarChar for CHAR、VARCHAR或TEXT的对象 用于NCHAR、NVARCHAR或NTEXT列的列或ctds.SqlNVarChar。 对于非Unicode列,应首先将值编码为 列的编码,例如拉丁语-1。默认情况下,ctds.SqlVarChar将 将str对象编码为utf-8,这对于大多数SQL来说可能是不正确的 服务器配置。 https://zillow.github.io/ctds/bulk_insert.htmltext-columns 行[col1]=\u到\u日期时间行[col1] 行[col2]=\u到\u介绍[col2] 行[col3]=\u到\u nvarcharrow[col3] 第[col4]行=第[col4]行至第[col4]行 返回行 def加载行: 时间 使用ctds.connect**DBCONFIG作为conn: 将conn.cursor作为游标: curs.executeTRUNCATE表MYSCHEMA.MYTABLE loaded_lines=conn.bulk_insertMYSCHEMA.MYTABLE,maptransform,行 时间 打印加载的行、加载的行、时间-时间 如果uuuu name uuuuu==\uuuuuuuu main\uuuuuuuu: loadread'data.csv'
请注意,ExecuteMy实际上并不执行真正的bulkinsert。在场景后面,它仍然会逐个插入。它实际上是一个包装器,允许以更pythonical的方式获取数据。这篇文章提供了一个合适的插页。我有以下错误,你能给我一个解决方案吗?pyodbc版本4.0.19和更高版本有一个快速执行选项,可以大大加快速度。有关详细信息,请参阅。我知道Executemany只能将吞吐量提高约1.5倍。有人可以确认吗?是否有方法将字段/列名列表传递到SQL语句中?我正在尝试将所有数据从一个表加载到另一个表。源表大约有60个字段,我希望我可以通过编程获得源中的字段列表,并在SQL语句中使用它,而不是在SQL语句中键入所有字段名。这是正确的答案,应该被接受。执行官
方法不能替代批量插入的速度。需要注意的是,如果您希望从迭代器而不是SQL Server本身上的文件执行大容量插入,ctds驱动程序是一个选项。只是刚刚签出了您提供的链接。我觉得它看起来真的很好。我要试试看。谢谢。由于更新,最好使用pyodbc而不是pyodbc。-这不再是事实。pyodbc仍在积极开发中,并得到Microsoft的正式支持。对于PyODBC,这两种说法都不正确。感谢您指出这一点。我注意到,自从我写了这篇文章以来,pyodbc有了很大的改进。这要求您的SQL实例在拉入该文件时能够访问该文件。最好通过实现SQL的大容量复制将其推送到数据库中。
import pyodbc
import contextlib

def bulk_insert(table_name, file_path):
    string = "BULK INSERT {} FROM '{}' (WITH FORMAT = 'CSV');"
    with contextlib.closing(pyodbc.connect("MYCONN")) as conn:
        with contextlib.closing(conn.cursor()) as cursor:
            cursor.execute(string.format(table_name, file_path))
        conn.commit()