到目前为止,我们已经讨论过 Insert
,这样我们就可以将一些数据放入我们的数据库中,然后花费大量时间在 Select
其处理用于从数据库检索数据的广泛的使用模式。在本节中,我们将介绍 Update
和 Delete
构造,这些构造用于修改现有行以及删除现有行。本节将从以核心为中心的角度介绍这些构造。
ORM阅读器 -正如在 插入带核心的行 ,即 Update
和 Delete
与ORM一起使用时,操作通常从 Session
对象作为 unit of work 进程。
然而,与之不同的是, Insert
,即 Update
和 Delete
构造也可以直接与ORM一起使用,使用一种称为“支持ORM的更新和删除”的模式;因此,熟悉这些构造对于ORM的使用很有用。这两种使用方式都在各节中进行了讨论。 更新ORM对象 和 删除ORM对象 。
这个 update()
函数会生成 Update
它表示SQL中的UPDATE语句,它将更新表中的现有数据。
就像 insert()
构造,有一种“传统”形式的 update()
,它一次针对一个表发出UPDATE,并且不返回任何行。但是,一些后端支持可以一次修改多个表的UPDATE语句,并且UPDATE语句还支持返回,以便匹配行中包含的列可以在结果集中返回。
基本更新如下::
>>> from sqlalchemy import update
>>> stmt = (
... update(user_table).where(user_table.c.name == 'patrick').
... values(fullname='Patrick the Star')
... )
>>> print(stmt)
UPDATE user_account SET fullname=:fullname WHERE user_account.name = :name_1
这个 Update.values()
方法控制UPDATE语句的Set元素的内容。这与 Insert
构造。通常可以使用列名作为关键字参数来传递参数。
UPDATE支持所有主要的SQL形式的UPDATE,包括针对表达式的UPDATE,我们可以使用 Column
表达式::
>>> stmt = (
... update(user_table).
... values(fullname="Username: " + user_table.c.name)
... )
>>> print(stmt)
UPDATE user_account SET fullname=(:name_1 || user_account.name)
为了在“ecutemany”上下文中支持UPDATE,在该上下文中,将针对同一语句调用多个参数集, bindparam()
构造可用于设置绑定参数;这些参数替换了文本值通常所在的位置:
>>> from sqlalchemy import bindparam
>>> stmt = (
... update(user_table).
... where(user_table.c.name == bindparam('oldname')).
... values(name=bindparam('newname'))
... )
>>> with engine.begin() as conn:
... conn.execute(
... stmt,
... [
... {'oldname':'jack', 'newname':'ed'},
... {'oldname':'wendy', 'newname':'mary'},
... {'oldname':'jim', 'newname':'jake'},
... ]
... )
BEGIN (implicit)
UPDATE user_account SET name=? WHERE user_account.name = ?
[...] (('ed', 'jack'), ('mary', 'wendy'), ('jake', 'jim'))
<sqlalchemy.engine.cursor.CursorResult object at 0x...>
COMMIT
可应用于更新的其他技术包括:
UPDATE语句可以通过使用 correlated subquery 。可以在可能放置列表达式的任何位置使用子查询::
>>> scalar_subq = (
... select(address_table.c.email_address).
... where(address_table.c.user_id == user_table.c.id).
... order_by(address_table.c.id).
... limit(1).
... scalar_subquery()
... )
>>> update_stmt = update(user_table).values(fullname=scalar_subq)
>>> print(update_stmt)
UPDATE user_account SET fullname=(SELECT address.email_address
FROM address
WHERE address.user_id = user_account.id ORDER BY address.id
LIMIT :param_1)
一些数据库(如PostgreSQL和MySQL)支持语法“update from”,其中附加表可以直接在特殊的FROM子句中声明。当其他表位于语句的WHERE子句中时,将隐式生成此语法::
>>> update_stmt = (
... update(user_table).
... where(user_table.c.id == address_table.c.user_id).
... where(address_table.c.email_address == 'patrick@aol.com').
... values(fullname='Pat')
... )
>>> print(update_stmt)
UPDATE user_account SET fullname=:fullname FROM address
WHERE user_account.id = address.user_id AND address.email_address = :email_address_1
还有一种特定于MySQL的语法可以更新多个表。这就需要我们参考 Table
VALUES子句中的对象,以便引用其他表:
>>> update_stmt = (
... update(user_table).
... where(user_table.c.id == address_table.c.user_id).
... where(address_table.c.email_address == 'patrick@aol.com').
... values(
... {
... user_table.c.fullname: "Pat",
... address_table.c.email_address: "pat@aol.com"
... }
... )
... )
>>> from sqlalchemy.dialects import mysql
>>> print(update_stmt.compile(dialect=mysql.dialect()))
UPDATE user_account, address
SET address.email_address=%s, user_account.fullname=%s
WHERE user_account.id = address.user_id AND address.email_address = %s
另一个仅限MySQL的行为是,UPDATE的SET子句中参数的顺序实际上会影响每个表达式的计算。对于此用例, Update.ordered_values()
方法接受元组序列,以便可以控制此顺序 2:
>>> update_stmt = (
... update(some_table).
... ordered_values(
... (some_table.c.y, 20),
... (some_table.c.x, some_table.c.y + 10)
... )
... )
>>> print(update_stmt)
UPDATE some_table SET y=:y, x=(some_table.y + :y_1)
而Python字典是 guaranteed to be insert ordered 从Python3.7开始, Update.ordered_values()
当MySQL UPDATE语句的SET子句必须以特定方式进行时,方法仍然提供了一种额外的意图清晰度度量。
这个 delete()
函数会生成 Delete
它表示SQL中的DELETE语句,它将从表中删除行。
这个 delete()
从API的角度来看,语句非常类似于 update()
构造,传统上不返回行,但允许在某些数据库后端上返回变体。
>>> from sqlalchemy import delete
>>> stmt = delete(user_table).where(user_table.c.name == 'patrick')
>>> print(stmt)
DELETE FROM user_account WHERE user_account.name = :name_1
喜欢 Update
, Delete
支持在WHERE子句中使用相关子查询以及特定于后端的多个表语法,例如 DELETE FROM..USING
在MySQL上::
>>> delete_stmt = (
... delete(user_table).
... where(user_table.c.id == address_table.c.user_id).
... where(address_table.c.email_address == 'patrick@aol.com')
... )
>>> from sqlalchemy.dialects import mysql
>>> print(delete_stmt.compile(dialect=mysql.dialect()))
DELETE FROM user_account USING user_account, address
WHERE user_account.id = address.user_id AND address.email_address = %s
两者都有 Update
和 Delete
对于使用Core调用的语句,支持在语句继续执行后返回匹配的行数 Connection
,即 Connection.execute()
。根据下面提到的注意事项,可以从 CursorResult.rowcount
属性:
>>> with engine.begin() as conn:
... result = conn.execute(
... update(user_table).
... values(fullname="Patrick McStar").
... where(user_table.c.name == 'patrick')
... )
... print(result.rowcount)
BEGIN (implicit)
UPDATE user_account SET fullname=? WHERE user_account.name = ?
[...] ('Patrick McStar', 'patrick')
1
COMMIT
小技巧
这个 CursorResult
类是的子类 Result
它包含特定于DBAPI的附加属性 cursor
对象。方法调用语句时,将返回此子类的实例 Connection.execute()
方法。使用ORM时, Session.execute()
方法为所有INSERT、UPDATE和DELETE语句返回此类型的对象。
关于以下方面的事实 CursorResult.rowcount
:
返回的值是行数 匹配的 通过语句的WHERE子句。行是否被实际修改并不重要。
CursorResult.rowcount
不一定可用于使用返回的UPDATE或DELETE语句。
对于 executemany 处决, CursorResult.rowcount
也可能不可用,这在很大程度上取决于正在使用的DBAPI模块以及配置的选项。该属性 CursorResult.supports_sane_multi_rowcount
指示此值是否可用于当前使用的后端。
某些驱动程序(特别是非关系数据库的第三方方言)可能不支持 CursorResult.rowcount
完全没有。这个 CursorResult.supports_sane_rowcount
会表明这一点。
ORM使用“rowcount” unit of work 验证UPDATE或DELETE语句是否与预期行数匹配的过程,也是文档中记录的ORM版本控制功能所必需的 配置版本计数器 。
就像 Insert
建造, Update
和 Delete
还支持通过使用 Update.returning()
和 Delete.returning()
方法。当在支持返回的后端上使用这些方法时,从与语句的WHERE条件匹配的所有行中选择的列将在 Result
对象作为可以迭代的行::
>>> update_stmt = (
... update(user_table).where(user_table.c.name == 'patrick').
... values(fullname='Patrick the Star').
... returning(user_table.c.id, user_table.c.name)
... )
>>> print(update_stmt)
UPDATE user_account SET fullname=:fullname
WHERE user_account.name = :name_1
RETURNING user_account.id, user_account.name
>>> delete_stmt = (
... delete(user_table).where(user_table.c.name == 'patrick').
... returning(user_table.c.id, user_table.c.name)
... )
>>> print(delete_stmt)
DELETE FROM user_account
WHERE user_account.name = :name_1
RETURNING user_account.id, user_account.name
SQLAlchemy 1.4 / 2.0 Tutorial
下一教程部分: 使用ORM进行数据操作
flambé! the dragon and The Alchemist image designs created and generously donated by Rotem Yaari.
Created using Sphinx 4.2.0.