来自 Python 的多行 UPSERT(插入或更新)
我目前正在使用 python 使用 pyodbc 执行下面的简单查询,以在 SQL Server 表中插入数据:
import pyodbc
table_name = 'my_table'
insert_values = [(1,2,3),(2,2,4),(3,4,5)]
cnxn = pyodbc.connect(...)
cursor = cnxn.cursor()
cursor.execute(
' '.join([
'insert into',
table_name,
'values',
','.join(
[str(i) for i in insert_values]
)
])
)
cursor.commit()
只要没有重复的键(假设第一列包含键),这应该可以工作。但是,对于具有重复键的数据(表中已存在的数据),它将引发错误。 如何使用 pyodbc 一次性在 SQL Server 表中插入多行,以便更新具有重复键的数据。
注意:有针对单行数据提出的解决方案,但是,我想一次插入多行(避免循环)!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这可以使用
MERGE
来完成。假设您有一个键列ID
,以及两列col_a
和col_b
(您需要在更新语句中指定列名称),那么声明如下所示:您可以在 rextester.com/IONFW62765 上尝试一下。
基本上,我正在使用值列表“即时”创建一个
Source
表,您想要更新插入。然后,当您将Source
表与Target
合并时,您可以测试MATCHED
条件 (Target.ID=Source.ID< /code>)(而当仅使用简单的
IF INSERT (...) ELSE UPDATE (...)
条件时,您将被限制为单行)。在使用
pyodbc
的 python 中,它可能应该如下所示:您可以在 SQL Server 文档。
This can be done using
MERGE
. Let's say you have a key columnID
, and two columnscol_a
andcol_b
(you need to specify column names in update statements), then the statement would look like this:You can give it a try on rextester.com/IONFW62765.
Basically, I'm creating a
Source
table "on-the-fly" using the list of values, which you want to upsert. When you then merge theSource
table with theTarget
, you can test theMATCHED
condition (Target.ID=Source.ID
) on each row (whereas you would be limited to a single row when just using a simpleIF <exists> INSERT (...) ELSE UPDATE (...)
condition).In python with
pyodbc
, it should probably look like this:You can read up more on
MERGE
in the SQL Server docs.跟进此处的现有答案,因为它们可能容易受到注入攻击,并且最好使用参数化查询(对于 mssql/pyodbc,这些是“?”占位符)。我稍微调整了 Alexander Novas 的代码,以便在带有 sqlalchemy 的查询的参数化版本中使用数据帧行:
如果您插入的字符串包含与 SQL 插入文本不兼容的字符(例如撇号,它会扰乱插入),则此方法也更好语句),因为它允许连接引擎处理参数化值(这也使其更安全地抵御 SQL 注入攻击)。
作为参考,我正在使用此代码创建引擎连接 - 您显然需要将其适应您的服务器/数据库/环境以及是否需要
fast_executemany
:编辑:我意识到这代码实际上根本不使用“占位符”表,而只是通过参数化命令直接从数据帧行复制值。
Following up on the existing answers here because they are potentially prone to injection attacks and it's better to use parameterized queries (for mssql/pyodbc, these are the "?" placeholders). I tweaked Alexander Novas's code slightly to use dataframe rows in a parameterized version of the query with sqlalchemy:
This method is also better if you are inserting strings with characters that aren't compatible with SQL insert text (such as apostrophes which mess up the insert statement) since it lets the connection engine handle the parameterized values (which also makes it safer against SQL injection attacks).
For reference, I'm creating the engine connection using this code - you'll obviously need to adapt it to your server/database/environment and whether or not you want
fast_executemany
:EDIT: I realized that this code does not actually make use of the "placeholder" table at all, and is just copying values directly from the dataframe rows by way of the parameterized command.
给定一个数据帧(df),我使用 ksbg 中的代码将其更新插入到表中。请注意,我在两列(日期和车站代码)上查找了匹配项,您可以使用其中一列。给定任何 df,代码生成查询。
Given a dataframe(df) I used the code from ksbg to upsert into a table. Note that I looked for a match on two columns (date and stationcode) you can use one. Code generates the query given any df.