如何使用SQLAlchemy Connection.execute()传递多个参数给INSERT INTO … VALUES?

huangapple go评论79阅读模式
英文:

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")])


huangapple
  • 本文由 发表于 2023年7月14日 05:42:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76683407.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定