英文:
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")])
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论