插入带核心的行

优质
小牛编辑
140浏览
2023-12-01

SQLAlchemy 1.4 / 2.0 Tutorial

此页是 SQLAlchemy 1.4/2.0教程

上一次: 使用数据 |下一步: |next|

插入带核心的行

使用Core时,SQL INSERT语句是使用 insert() 函数-此函数生成 Insert 表示SQL中的INSERT语句,将新数据添加到表中。

ORM阅读器 -从ORM的角度将行插入数据库的方式在 Session 对象,称为 unit of work 过程,并且与这里描述的仅核心方法有很大的不同。更多关注ORM的部分稍后从 使用ORM插入行 在表达式语言部分之后,我们将介绍这一点。

INSERT()SQL表达式构造

以下是一个简单的示例 Insert 同时说明目标表和VALUES子句::

>>> from sqlalchemy import insert
>>> stmt = insert(user_table).values(name='spongebob', fullname="Spongebob Squarepants")

以上内容 stmt 变量是 Insert 。大多数SQL表达式都可以就地串行化,作为查看所生成内容的一般形式的一种方式:

>>> print(stmt)
INSERT INTO user_account (name, fullname) VALUES (:name, :fullname)

字符串形式是通过生成 Compiled 对象的形式,包括语句的特定于数据库的字符串SQL表示形式;我们可以直接使用 ClauseElement.compile() 方法:

>>> compiled = stmt.compile()

我们的 Insert 构造是“参数化”构造的一个示例,前面在 发送参数 ;要查看 namefullname bound parameters ,可从 Compiled 同时构造::

>>> compiled.params
{'name': 'spongebob', 'fullname': 'Spongebob Squarepants'}

执行该语句

调用我们可以向其中插入行的语句 user_table 。可以在SQL日志中看到INSERT SQL以及绑定的参数:

>>> with engine.connect() as conn:
...     result = conn.execute(stmt)
...     conn.commit()
BEGIN (implicit)
INSERT INTO user_account (name, fullname) VALUES (?, ?)
[...] ('spongebob', 'Spongebob Squarepants')
COMMIT

在上面的简单形式中,INSERT语句不返回任何行,如果只插入了一行,它通常可以返回有关该行插入期间生成的列级默认值的信息,最常见的是整数主键值。在上述情况下,SQLite数据库中的第一行通常会返回 1 对于第一个整数主键值,我们可以使用 CursorResult.inserted_primary_key 访问者:

>>> result.inserted_primary_key
(1,)

小技巧

CursorResult.inserted_primary_key 返回元组,因为主键可能包含多列。这称为 composite primary key 。这个 CursorResult.inserted_primary_key 旨在始终包含刚插入的记录的完整主键,而不仅仅是“cursor.lastrowid”类型的值,而且还用于填充,而不管是否使用了“自动增量”,因此为了表示完整的主键,它是一个元组。

在 1.4.8 版更改: 返回的元组 CursorResult.inserted_primary_key 现在是一个命名元组,通过将其作为 Row 对象。

INSERT通常自动生成“VALUES”子句

上面的示例利用了 Insert.values() 方法显式创建SQL INSERT语句的VALUES子句。此方法实际上有一些变体,允许特殊形式,如一条语句中的多行和插入SQL表达式。不过,按照通常的方式 Insert 是这样的,因此VALUES子句是从传递给 Connection.execute() 方法;下面我们再插入两行来说明这一点:

>>> with engine.connect() as conn:
...     result = conn.execute(
...         insert(user_table),
...         [
...             {"name": "sandy", "fullname": "Sandy Cheeks"},
...             {"name": "patrick", "fullname": "Patrick Star"}
...         ]
...     )
...     conn.commit()
BEGIN (implicit)
INSERT INTO user_account (name, fullname) VALUES (?, ?)
[...] (('sandy', 'Sandy Cheeks'), ('patrick', 'Patrick Star'))
COMMIT

上面的执行以“ecutemany”表单为特征,首先在 发送多个参数 但是,与使用 text() 构造,我们不必拼写任何SQL。通过将词典或词典列表传递给 Connection.execute() 方法与 Insert 构造,即 Connection 方法的VALUES子句中表示传递的列名 Insert 自动构建。

Deep Alchemy

大家好,欢迎收看第一期的 深度炼金术 。左边的人被称为 炼金术士 ,你会注意到它们是 not 一个巫师,因为尖顶的帽子没有竖起来。炼金术士来描述的东西一般是 more advanced and/or tricky 另外, 通常不需要 ,但是无论出于什么原因,他们都认为您应该知道SQLAlChemy可以做的这件事。

在这一版中,我们的目标是将一些有趣的数据放在 address_table 同样,下面是一个更高级的示例,说明 Insert.values() 方法可以显式使用,同时包括从参数生成的附加值。一个 scalar subquery 是构造的,它利用 select() 构造,子查询中使用的参数是使用显式绑定参数名设置的,该绑定参数名是使用 bindparam() 构造。

这是一些微不足道的 更深一层 炼金术,这样我们就可以添加相关行,而无需从 user_table 操作添加到应用程序中。大多数炼金术士会简单地使用ORM,它会为我们处理这样的事情。

>>> from sqlalchemy import select, bindparam
>>> scalar_subq = (
...     select(user_table.c.id).
...     where(user_table.c.name==bindparam('username')).
...     scalar_subquery()
... )

>>> with engine.connect() as conn:
...     result = conn.execute(
...         insert(address_table).values(user_id=scalar_subq),
...         [
...             {"username": 'spongebob', "email_address": "spongebob@sqlalchemy.org"},
...             {"username": 'sandy', "email_address": "sandy@sqlalchemy.org"},
...             {"username": 'sandy', "email_address": "sandy@squirrelpower.org"},
...         ]
...     )
...     conn.commit()
BEGIN (implicit)
INSERT INTO address (user_id, email_address) VALUES ((SELECT user_account.id
FROM user_account
WHERE user_account.name = ?), ?)
[...] (('spongebob', 'spongebob@sqlalchemy.org'), ('sandy', 'sandy@sqlalchemy.org'),
('sandy', 'sandy@squirrelpower.org'))
COMMIT

插入.从SELECT

这个 Insert 构造可以组成一个插入,该插入使用 Insert.from_select() 方法:

>>> select_stmt = select(user_table.c.id, user_table.c.name + "@aol.com")
>>> insert_stmt = insert(address_table).from_select(
...     ["user_id", "email_address"], select_stmt
... )
>>> print(insert_stmt)
INSERT INTO address (user_id, email_address)
SELECT user_account.id, user_account.name || :name_1 AS anon_1
FROM user_account

INSERT...RETURNING

自动使用受支持后端的RETURNING子句来检索最后插入的主键值以及服务器默认值的值。但是,返回子句也可以使用 Insert.returning() 方法;在本例中, Result 执行语句时返回的对象具有可以提取的行::

>>> insert_stmt = insert(address_table).returning(address_table.c.id, address_table.c.email_address)
>>> print(insert_stmt)
INSERT INTO address (id, user_id, email_address)
VALUES (:id, :user_id, :email_address)
RETURNING address.id, address.email_address

它还可以与 Insert.from_select() ,如下面的示例所示,该示例构建于 插入.从SELECT ::

>>> select_stmt = select(user_table.c.id, user_table.c.name + "@aol.com")
>>> insert_stmt = insert(address_table).from_select(
...     ["user_id", "email_address"], select_stmt
... )
>>> print(insert_stmt.returning(address_table.c.id, address_table.c.email_address))
INSERT INTO address (user_id, email_address)
SELECT user_account.id, user_account.name || :name_1 AS anon_1
FROM user_account RETURNING address.id, address.email_address

小技巧

UPDATE和DELETE语句也支持返回功能,本教程稍后将介绍这两条语句。返回的特征通常是 1 仅支持使用一组绑定参数的语句执行;也就是说,它不能与 发送多个参数 。此外,某些方言(如Oracle方言)只允许返回整个单行,这意味着它不能与“INSERT..FROM SELECT”一起使用,也不能与多行一起使用 UpdateDelete 表格。

1

有内部支持,支持 psycopg2 一次插入多行的方言,并且还支持返回,SQLAlChemy ORM利用了这一点。但是,该特性尚未推广到所有方言,并且还不是SQLAlChemy常规API的一部分。

参见

Insert -在SQL表达式API文档中

SQLAlchemy 1.4 / 2.0 Tutorial

下一教程部分: 使用核心或ORM选择行