SQLAlchemy INSERT stmt with OUTPUT return 多行
SQLAlchemy INSERT stmt with OUTPUT return multiple rows
当我使用 sqlalchemy 插入多行时,我没有得到插入的 id 值。
例如,当我在 MS SQL 服务器中执行纯 SQL 时,它在结果集中显示 2 行(我插入的记录...1,2)。
INSERT INTO dbo.emp (id, fname, lname, dob)
OUTPUT inserted.id
VALUES (1, 'Test1','Rec1','01/01/1990'), (2, 'Test2','Rec2','01/01/1990')
当我使用下面的代码在 sqlalchemy 中执行相同的查询时,打印语句只显示值 2(而不是 1)。看起来结果集插入了最后一行。下面的代码有什么问题吗?
try:
sql = """\
INSERT INTO dbo.emp (id, fname, lname, dob)
OUTPUT inserted.id
VALUES (:id, :fname, :lname, :dob)
"""
stmt = text(sql)
data = [
{'id': 1, 'fname':'Test1', 'lname':'rec1', 'dob':'05/05/2000'}
,{'id': 2, 'fname': 'Test2', 'lname': 'rec2', 'dob': '05/05/2001'}
]
result = conn.execute(stmt, data)
for id in result:
print(id)
conn.commit()
except exc.IntegrityError as e:
print('Code3 - Integrity error raised', e)
conn.rollback()
except exc.SQLAlchemyError as e:
print('Code3 - Something else went wrong', e)
conn.rollback()
我很确定 conn.execute 运行 插入命令两次。看,您的 sql 命令是一个数据行的插入,因此它不会转换为:
INSERT INTO dbo.emp (id, fname, lname, dob)
OUTPUT inserted.id
VALUES (1, 'Test1','Rec1','01/01/1990'), (2, 'Test2','Rec2','01/01/1990')
相反,插入的 2 个命令是连续 运行,而 sqlalchemy 似乎只保留第二个结果。 (我试图深入研究 sqlalchemy 代码,但找不到它发生的地方)。
如果你真的想使用 sqlalchemy 的力量,我建议至少使用 sqlalchemy 查询语言,让 sqlalchemy 构建你的 sql命令。查找 SQL 表达式语言教程以开始使用。
对于像字典列表这样的多行参数数据,SQLAlchemy 使用 pyodbc 的 .executemany() 方法,该方法不是 suitable 从 OUTPUT 子句返回多个结果。
如果您使用的是 SQL Server 2016+,您可以使用 OPENJSON
并传递表示多行数据的单个字符串来获取结果:
import json
import sqlalchemy as sa
engine = sa.create_engine("mssql+pyodbc://@mssqlLocal")
with engine.begin() as conn:
conn.exec_driver_sql("DROP TABLE IF EXISTS emp")
conn.exec_driver_sql(
"CREATE TABLE emp ("
"id int identity primary key, "
"fname nvarchar(50), "
"lname nvarchar(50)"
")"
)
sql = """\
INSERT INTO emp (fname, lname)
OUTPUT inserted.id
SELECT fname, lname FROM
OPENJSON(:json_str)
WITH (
fname nvarchar(50) '$.fname',
lname nvarchar(50) '$.lname'
)
"""
data = [
{"fname": "Homer", "lname": "Simpson"},
{"fname": "Ned", "lname": "Flanders"},
]
with engine.begin() as conn:
results = conn.execute(
sa.text(sql), {"json_str": json.dumps(data)}
).fetchall()
print(results) # [(1,), (2,)]
对于旧版本的 SQL 服务器,您可以将行数据上传到临时 table 然后使用
INSERT INTO emp (fname, lname)
OUTPUT inserted.id
SELECT fname, lname FROM #temp_table
当我使用 sqlalchemy 插入多行时,我没有得到插入的 id 值。
例如,当我在 MS SQL 服务器中执行纯 SQL 时,它在结果集中显示 2 行(我插入的记录...1,2)。
INSERT INTO dbo.emp (id, fname, lname, dob)
OUTPUT inserted.id
VALUES (1, 'Test1','Rec1','01/01/1990'), (2, 'Test2','Rec2','01/01/1990')
当我使用下面的代码在 sqlalchemy 中执行相同的查询时,打印语句只显示值 2(而不是 1)。看起来结果集插入了最后一行。下面的代码有什么问题吗?
try:
sql = """\
INSERT INTO dbo.emp (id, fname, lname, dob)
OUTPUT inserted.id
VALUES (:id, :fname, :lname, :dob)
"""
stmt = text(sql)
data = [
{'id': 1, 'fname':'Test1', 'lname':'rec1', 'dob':'05/05/2000'}
,{'id': 2, 'fname': 'Test2', 'lname': 'rec2', 'dob': '05/05/2001'}
]
result = conn.execute(stmt, data)
for id in result:
print(id)
conn.commit()
except exc.IntegrityError as e:
print('Code3 - Integrity error raised', e)
conn.rollback()
except exc.SQLAlchemyError as e:
print('Code3 - Something else went wrong', e)
conn.rollback()
我很确定 conn.execute 运行 插入命令两次。看,您的 sql 命令是一个数据行的插入,因此它不会转换为:
INSERT INTO dbo.emp (id, fname, lname, dob)
OUTPUT inserted.id
VALUES (1, 'Test1','Rec1','01/01/1990'), (2, 'Test2','Rec2','01/01/1990')
相反,插入的 2 个命令是连续 运行,而 sqlalchemy 似乎只保留第二个结果。 (我试图深入研究 sqlalchemy 代码,但找不到它发生的地方)。
如果你真的想使用 sqlalchemy 的力量,我建议至少使用 sqlalchemy 查询语言,让 sqlalchemy 构建你的 sql命令。查找 SQL 表达式语言教程以开始使用。
对于像字典列表这样的多行参数数据,SQLAlchemy 使用 pyodbc 的 .executemany() 方法,该方法不是 suitable 从 OUTPUT 子句返回多个结果。
如果您使用的是 SQL Server 2016+,您可以使用 OPENJSON
并传递表示多行数据的单个字符串来获取结果:
import json
import sqlalchemy as sa
engine = sa.create_engine("mssql+pyodbc://@mssqlLocal")
with engine.begin() as conn:
conn.exec_driver_sql("DROP TABLE IF EXISTS emp")
conn.exec_driver_sql(
"CREATE TABLE emp ("
"id int identity primary key, "
"fname nvarchar(50), "
"lname nvarchar(50)"
")"
)
sql = """\
INSERT INTO emp (fname, lname)
OUTPUT inserted.id
SELECT fname, lname FROM
OPENJSON(:json_str)
WITH (
fname nvarchar(50) '$.fname',
lname nvarchar(50) '$.lname'
)
"""
data = [
{"fname": "Homer", "lname": "Simpson"},
{"fname": "Ned", "lname": "Flanders"},
]
with engine.begin() as conn:
results = conn.execute(
sa.text(sql), {"json_str": json.dumps(data)}
).fetchall()
print(results) # [(1,), (2,)]
对于旧版本的 SQL 服务器,您可以将行数据上传到临时 table 然后使用
INSERT INTO emp (fname, lname)
OUTPUT inserted.id
SELECT fname, lname FROM #temp_table