英文:
How to pass multiple parameters to INSERT INTO ... VALUES using SQLAlchemy Connection.execute()?
问题
以下是适用于PostgreSQL的有效SQL语句。
INSERT INTO schema.table (id, letter)
VALUES
(1, 'a'),
(2, 'b'),
...
我想使用SQLAlchemy执行类似的参数化语句。我正在使用SQLAlchemy 1.4的Connection.execute()
,但我无法访问表映射类(ORM模型)。
以下的示例不起作用,但演示了我试图实现的目标。
statement: str = """
INSERT INTO schema.table (id, letter)
VALUES :values
"""
values: Tuple[Tuple[int, str], ...] = (
(1, 'a'),
(2, 'b'),
)
with engine.connect() as connection:
connection.execute(
sqlalchemy.text(statement),
{"values": values},
)
在这个确切的示例中,values
是一个元组;它被绑定为一个元组的元组,这不符合我的目标("INSERT has more expressions than target columns")。同样,使用元组列表会创建一个SQL ARRAY
。
> 问: 为什么不只是使用f字符串或"..."
.format(...)`?
> 答: 我听说这是不良实践。
问题: 如何正确“解包”values
参数?或者,如何以最佳方式实现我所寻求的目标(而不使用Table
ORM类)?
* 是的,我知道在提问时SQLAlchemy 1.4已经不再维护。
英文:
The following is valid SQL for PostgreSQL.
INSERT INTO schema.table (id, letter)
VALUES
(1, 'a'),
(2, 'b'),
...
I would like to execute a similar, parameterized statement using SQLAlchemy. I am using SQLAlchemy 1.4* Connection.execute()
, but I do not have access to the table mapper class (ORM model).
The following does not work, but does demonstrate what I am trying to achieve.
statement: str = """
INSERT INTO schema.table (id, letter)
VALUES :values
"""
values: Tuple[Tuple[int, str], ...] = (
(1, "a"),
(2, "b"),
)
with engine.connect() as connection:
connection.execute(
sqlalchemy.text(statement),
{"values": values},
)
In this exact example, values
is a tuple; it gets bound as a tuple of tuples, which does not fit what I am trying to achieve ("INSERT has more expressions than target columns"). Likewise, using a list of tuples creates a SQL ARRAY
.
> Q: Why don't you just use an f-string or "...".format(...)
?
> A: I've read that this is poor practice.
Question: How can I properly "unpack" the values
parameters? Alternatively, what is the best way to achieve what I am seeking (without using the Table
ORM class)?
* Yes, I am aware that SQLAlchemy 1.4 is deprecated at the time of this question's posting.
答案1
得分: 1
你可以使用以下方式,你几乎就完成了,只需要更改插入查询并将绑定设置为字典列表。
正如在文档中所示,稍微修改以适应你的用例。
statement: str = "INSERT INTO schema.table (id, letter) VALUES (:id, :letter)"
values = (
(1, "a"),
(2, "b"),
)
values = [{'id': id, 'letter': letter} for id, letter in values]
with engine.connect() as connection:
connection.execute(text(statement), values)
英文:
You can use the following, you were almost there, you just had to change the insert query and make the binding as a list of dicts.
As seen in the docs
and slightly modified for your use-case.
statement: str = "INSERT INTO schema.table (id, letter) VALUES (:id, :letter)"
values = (
(1, "a"),
(2, "b"),
)
values = [{'id': id, 'letter': letter} for id, letter in values]
with engine.connect() as connection:
connection.execute(text(statement), values)
答案2
得分: 1
使用字典似乎可以工作,但我认为更正确的版本使用 insert().values()
和一个 Table
对象。你无法生成 Table
对象吗?
with engine.connect() as conn, conn.begin():
stmt = text("INSERT INTO users (id, name) VALUES(:id, :name)")
conn.execute(stmt, [dict(id=1, name="test"), dict(id=2, name="testagain")])
英文:
Using dictionaries seems to work but I think the more correct version uses insert().values()
and a Table
object. Are you not able to generate the Table
object?
with engine.connect() as conn, conn.begin():
stmt = text("INSERT INTO users (id, name) VALUES(:id, :name)")
conn.execute(stmt, [dict(id=1, name="test"), dict(id=2, name="testagain")])
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论