SqlAlchemy 2.0 中文文档(十七)(1)

简介: SqlAlchemy 2.0 中文文档(十七)


原文:docs.sqlalchemy.org/en/20/contents.html

ORM-启用的 INSERT、UPDATE 和 DELETE 语句

原文:docs.sqlalchemy.org/en/20/orm/queryguide/dml.html

关于本文档

本节利用了首次在 SQLAlchemy 统一教程中展示的 ORM 映射,如声明映射类一节所示,以及映射类继承层次结构一节中展示的继承映射。

查看此页面的 ORM 设置。

除了处理 ORM 启用的Select对象外,Session.execute()方法还可以容纳 ORM 启用的InsertUpdateDelete对象,它们分别以各种方式用于一次性插入、更新或删除多个数据库行。此外,还有特定于方言的支持 ORM 启用的“upserts”,这是一种自动使用 UPDATE 来处理已经存在的行的 INSERT 语句。

下表总结了本文讨论的调用形式:

ORM 用例 使用的 DML 构造 使用以下方式传递数据 是否支持 RETURNING? 是否支持多表映射?
ORM 批量插入语句 insert() 字典列表到Session.execute.params
使用 SQL 表达式的 ORM 批量插入 insert() 使用Insert.values()Session.execute.params
使用每行 SQL 表达式进行 ORM 批量插入 insert() 字典列表Insert.values()
ORM “upsert” 语句 insert() 字典列表Insert.values()
通过主键进行 ORM 批量更新 update() 字典列表Session.execute.params
使用自定义 WHERE 条件的 ORM UPDATE 和 DELETE update(), delete() 关键字Update.values() 部分,需要手动步骤

ORM 批量插入语句

一个insert()构造可以根据 ORM 类构建,并传递给Session.execute()方法。发送到Session.execute.params参数的参数字典列表,与Insert对象本身分开,将为语句调用批量插入模式,这基本上意味着该操作将尽可能地优化多行:

>>> from sqlalchemy import insert
>>> session.execute(
...     insert(User),
...     [
...         {"name": "spongebob", "fullname": "Spongebob Squarepants"},
...         {"name": "sandy", "fullname": "Sandy Cheeks"},
...         {"name": "patrick", "fullname": "Patrick Star"},
...         {"name": "squidward", "fullname": "Squidward Tentacles"},
...         {"name": "ehkrabs", "fullname": "Eugene H. Krabs"},
...     ],
... )
INSERT  INTO  user_account  (name,  fullname)  VALUES  (?,  ?)
[...]  [('spongebob',  'Spongebob Squarepants'),  ('sandy',  'Sandy Cheeks'),  ('patrick',  'Patrick Star'),
('squidward',  'Squidward Tentacles'),  ('ehkrabs',  'Eugene H. Krabs')]
<...>

参数字典包含键/值对,这些对应于 ORM 映射属性,与映射的Columnmapped_column()声明以及复合声明对齐,如果这两个名称恰好不同,则键应与ORM 映射属性名称匹配,而不是实际数据库列名称。

在 2.0 版本中更改:将 Insert 构造传递给 Session.execute() 方法现在会调用“批量插入”,这使用了与传统的 Session.bulk_insert_mappings() 方法相同的功能。这是与 1.x 系列相比的行为变更,在那里 Insert 将以 Core 为中心的方式解释,使用列名作为值键;现在接受 ORM 属性键。通过将执行选项 {"dml_strategy": "raw"}传递给 Session.execute()Session.execution_options 参数,可以使用 Core 风格的功能。

使用 RETURNING 获取新对象

批量 ORM 插入功能支持选定后端的 INSERT…RETURNING,该功能可以返回一个Result对象,该对象可能会返回单个列以及对应于新生成记录的完全构造的  ORM 对象。INSERT…RETURNING 需要使用支持 SQL RETURNING 语法以及支持带 RETURNING 的  executemany 的后端;除了 MySQL(MariaDB 已包含在内)外,此功能适用于所有 SQLAlchemy 包含的 后端。

举个例子,我们可以运行与之前相同的语句,同时使用 UpdateBase.returning() 方法,将完整的 User 实体作为我们希望返回的内容传递进去。 Session.scalars() 用于允许迭代 User 对象:

>>> users = session.scalars(
...     insert(User).returning(User),
...     [
...         {"name": "spongebob", "fullname": "Spongebob Squarepants"},
...         {"name": "sandy", "fullname": "Sandy Cheeks"},
...         {"name": "patrick", "fullname": "Patrick Star"},
...         {"name": "squidward", "fullname": "Squidward Tentacles"},
...         {"name": "ehkrabs", "fullname": "Eugene H. Krabs"},
...     ],
... )
INSERT  INTO  user_account  (name,  fullname)
VALUES  (?,  ?),  (?,  ?),  (?,  ?),  (?,  ?),  (?,  ?)
RETURNING  id,  name,  fullname,  species
[...]  ('spongebob',  'Spongebob Squarepants',  'sandy',  'Sandy Cheeks',
'patrick',  'Patrick Star',  'squidward',  'Squidward Tentacles',
'ehkrabs',  'Eugene H. Krabs')
>>> print(users.all())
[User(name='spongebob', fullname='Spongebob Squarepants'),
 User(name='sandy', fullname='Sandy Cheeks'),
 User(name='patrick', fullname='Patrick Star'),
 User(name='squidward', fullname='Squidward Tentacles'),
 User(name='ehkrabs', fullname='Eugene H. Krabs')]

在上面的例子中,渲染的 SQL 采用了由 SQLite 后端请求的插入多个值功能所使用的形式,在这里,单个参数字典被嵌入到一个单个的 INSERT 语句中,以便可以使用 RETURNING。

从版本 2.0 开始更改:ORM Session 现在在 ORM 上下文中解释来自 InsertUpdate 甚至 Delete 构造的 RETURNING 子句,这意味着可以传递一种混合的列表达式和 ORM 映射实体到 Insert.returning() 方法中,然后将以 ORM 结果从构造物如 Select 中提供的方式传递,包括映射实体将以 ORM 映射对象的形式在结果中提供。还存在对 ORM 加载器选项(如 load_only()selectinload())的有限支持。

将返回的记录与输入数据顺序相关联

在使用带 RETURNING 的批量 INSERT 时,重要的是要注意,大多数数据库后端不提供返回的 RETURNING  记录的顺序的正式保证,包括不保证它们的顺序与输入记录的顺序相对应。对于需要确保 RETURNING  记录能够与输入数据相关联的应用程序,可以指定额外的参数 Insert.returning.sort_by_parameter_order,这依赖于后端可能使用特殊的 INSERT 形式来维护一个标记,该标记用于适当地重新排序返回的行,或者在某些情况下,例如在下面使用 SQLite 后端的示例中,该操作将逐行插入:

>>> data = [
...     {"name": "pearl", "fullname": "Pearl Krabs"},
...     {"name": "plankton", "fullname": "Plankton"},
...     {"name": "gary", "fullname": "Gary"},
... ]
>>> user_ids = session.scalars(
...     insert(User).returning(User.id, sort_by_parameter_order=True), data
... )
INSERT  INTO  user_account  (name,  fullname)  VALUES  (?,  ?)  RETURNING  id
[...  (insertmanyvalues)  1/3  (ordered;  batch  not  supported)]  ('pearl',  'Pearl Krabs')
INSERT  INTO  user_account  (name,  fullname)  VALUES  (?,  ?)  RETURNING  id
[insertmanyvalues  2/3  (ordered;  batch  not  supported)]  ('plankton',  'Plankton')
INSERT  INTO  user_account  (name,  fullname)  VALUES  (?,  ?)  RETURNING  id
[insertmanyvalues  3/3  (ordered;  batch  not  supported)]  ('gary',  'Gary')
>>> for user_id, input_record in zip(user_ids, data):
...     input_record["id"] = user_id
>>> print(data)
[{'name': 'pearl', 'fullname': 'Pearl Krabs', 'id': 6},
{'name': 'plankton', 'fullname': 'Plankton', 'id': 7},
{'name': 'gary', 'fullname': 'Gary', 'id': 8}]

2.0.10 新功能:添加了 Insert.returning.sort_by_parameter_order,该功能在 insertmanyvalues 架构中实现。

参见

将返回的行与参数集相关联 - 介绍了确保输入数据和结果行之间对应关系的方法背景,而不会显著降低性能 ### 使用异构参数字典

ORM 批量插入功能支持“异构”的参数字典列表,这基本上意味着“各个字典可以具有不同的键”。当检测到这种情况时,ORM 将根据每个键集将参数字典分组,并相应地批处理到单独的 INSERT 语句中:

>>> users = session.scalars(
...     insert(User).returning(User),
...     [
...         {
...             "name": "spongebob",
...             "fullname": "Spongebob Squarepants",
...             "species": "Sea Sponge",
...         },
...         {"name": "sandy", "fullname": "Sandy Cheeks", "species": "Squirrel"},
...         {"name": "patrick", "species": "Starfish"},
...         {
...             "name": "squidward",
...             "fullname": "Squidward Tentacles",
...             "species": "Squid",
...         },
...         {"name": "ehkrabs", "fullname": "Eugene H. Krabs", "species": "Crab"},
...     ],
... )
INSERT  INTO  user_account  (name,  fullname,  species)
VALUES  (?,  ?,  ?),  (?,  ?,  ?)  RETURNING  id,  name,  fullname,  species
[...  (insertmanyvalues)  1/1  (unordered)]  ('spongebob',  'Spongebob Squarepants',  'Sea Sponge',
'sandy',  'Sandy Cheeks',  'Squirrel')
INSERT  INTO  user_account  (name,  species)
VALUES  (?,  ?)  RETURNING  id,  name,  fullname,  species
[...]  ('patrick',  'Starfish')
INSERT  INTO  user_account  (name,  fullname,  species)
VALUES  (?,  ?,  ?),  (?,  ?,  ?)  RETURNING  id,  name,  fullname,  species
[...  (insertmanyvalues)  1/1  (unordered)]  ('squidward',  'Squidward Tentacles',
'Squid',  'ehkrabs',  'Eugene H. Krabs',  'Crab') 

在上面的例子中,传递的五个参数字典被转换为三个 INSERT 语句,按照每个字典中特定的键集分组,同时仍保持行顺序,即("name", "fullname", "species")("name", "species")("name","fullname", "species")。### 在 ORM 批量 INSERT 语句中发送 NULL 值

批量 ORM 插入功能利用了遗留“批量”插入行为以及总体 ORM 工作单元中存在的行为,即包含 NULL 值的行使用不引用这些列的语句进行  INSERT;这样做的理由是,包含服务器端 INSERT 默认值的后端和模式可能对 NULL  值与没有值的存在敏感,并且会产生预期的服务器端值。这种默认行为会将批量插入的批次分解为更多的行数较少的批次:

>>> session.execute(
...     insert(User),
...     [
...         {
...             "name": "name_a",
...             "fullname": "Employee A",
...             "species": "Squid",
...         },
...         {
...             "name": "name_b",
...             "fullname": "Employee B",
...             "species": "Squirrel",
...         },
...         {
...             "name": "name_c",
...             "fullname": "Employee C",
...             "species": None,
...         },
...         {
...             "name": "name_d",
...             "fullname": "Employee D",
...             "species": "Bluefish",
...         },
...     ],
... )
INSERT  INTO  user_account  (name,  fullname,  species)  VALUES  (?,  ?,  ?)
[...]  [('name_a',  'Employee A',  'Squid'),  ('name_b',  'Employee B',  'Squirrel')]
INSERT  INTO  user_account  (name,  fullname)  VALUES  (?,  ?)
[...]  ('name_c',  'Employee C')
INSERT  INTO  user_account  (name,  fullname,  species)  VALUES  (?,  ?,  ?)
[...]  ('name_d',  'Employee D',  'Bluefish')
... 

在上面,四行的批量 INSERT 被分解成三个单独的语句,第二个语句重新格式化,不再引用包含None值的单个参数字典的  NULL 列。当数据集中的许多行包含随机 NULL  值时,这种默认行为可能是不希望的,因为它会导致“executemany”操作被分解为更多的较小操作;特别是当依赖于  insertmanyvalues 来减少总语句数时,这可能会产生更大的性能影响。

要禁用对参数中的None值进行分批处理的操作,请传递执行选项render_nulls=True;这将导致所有参数字典被等效处理,假定每个字典中具有相同的键集:

>>> session.execute(
...     insert(User).execution_options(render_nulls=True),
...     [
...         {
...             "name": "name_a",
...             "fullname": "Employee A",
...             "species": "Squid",
...         },
...         {
...             "name": "name_b",
...             "fullname": "Employee B",
...             "species": "Squirrel",
...         },
...         {
...             "name": "name_c",
...             "fullname": "Employee C",
...             "species": None,
...         },
...         {
...             "name": "name_d",
...             "fullname": "Employee D",
...             "species": "Bluefish",
...         },
...     ],
... )
INSERT  INTO  user_account  (name,  fullname,  species)  VALUES  (?,  ?,  ?)
[...]  [('name_a',  'Employee A',  'Squid'),  ('name_b',  'Employee B',  'Squirrel'),  ('name_c',  'Employee C',  None),  ('name_d',  'Employee D',  'Bluefish')]
... 

在上面,所有的参数字典都被发送到一个单独的 INSERT 批处理中,包括第三个参数字典中存在的None值。

新版本 2.0.23 中:添加了render_nulls执行选项,该选项反映了遗留的Session.bulk_insert_mappings.render_nulls参数的行为。### 用于连接表继承的批量 INSERT

ORM 批量插入建立在传统的工作单元系统使用的内部系统之上,以发出 INSERT 语句。这意味着对于映射到多个表的 ORM  实体,通常是使用联接表继承进行映射的实体,批量插入操作将为映射表示的每个表发出一个 INSERT  语句,正确地将服务器生成的主键值传递给依赖于它们的表行。此处还支持 RETURNING 功能,ORM 将为执行的每个 INSERT 语句接收Result对象,然后“水平拼接”它们,以便返回的行包括插入的所有列的值:

>>> managers = session.scalars(
...     insert(Manager).returning(Manager),
...     [
...         {"name": "sandy", "manager_name": "Sandy Cheeks"},
...         {"name": "ehkrabs", "manager_name": "Eugene H. Krabs"},
...     ],
... )
INSERT  INTO  employee  (name,  type)  VALUES  (?,  ?)  RETURNING  id,  name,  type
[...  (insertmanyvalues)  1/2  (ordered;  batch  not  supported)]  ('sandy',  'manager')
INSERT  INTO  employee  (name,  type)  VALUES  (?,  ?)  RETURNING  id,  name,  type
[insertmanyvalues  2/2  (ordered;  batch  not  supported)]  ('ehkrabs',  'manager')
INSERT  INTO  manager  (id,  manager_name)  VALUES  (?,  ?),  (?,  ?)  RETURNING  id,  manager_name,  id  AS  id__1
[...  (insertmanyvalues)  1/1  (ordered)]  (1,  'Sandy Cheeks',  2,  'Eugene H. Krabs') 

提示

加入继承映射的批量插入要求 ORM 在内部使用Insert.returning.sort_by_parameter_order参数,以便它可以将来自基表的  RETURNING 行的主键值与用于插入“子”表的参数集相关联,这就是为什么上面示例中的 SQLite  后端会透明地降级到使用非批量语句。有关此功能的背景信息,请参阅将 RETURNING 行与参数集相关联。### 使用 SQL 表达式进行 ORM  批量插入

ORM 批量插入功能支持添加一组固定的参数,其中可能包括要应用于每个目标行的 SQL 表达式。为了实现这一点,结合使用Insert.values()方法,传递一个将应用于所有行的参数字典,以及在调用Session.execute()时包含包含单个行值的参数字典列表的常规批量调用形式。

例如,给定一个包含“timestamp”列的 ORM 映射:

import datetime
class LogRecord(Base):
    __tablename__ = "log_record"
    id: Mapped[int] = mapped_column(primary_key=True)
    message: Mapped[str]
    code: Mapped[str]
    timestamp: Mapped[datetime.datetime]

如果我们想要插入一系列具有唯一message字段的LogRecord元素,但是我们希望对所有行应用 SQL 函数now(),我们可以在Insert.values()中传递timestamp,然后使用“bulk”模式传递额外的记录:

>>> from sqlalchemy import func
>>> log_record_result = session.scalars(
...     insert(LogRecord).values(code="SQLA", timestamp=func.now()).returning(LogRecord),
...     [
...         {"message": "log message #1"},
...         {"message": "log message #2"},
...         {"message": "log message #3"},
...         {"message": "log message #4"},
...     ],
... )
INSERT  INTO  log_record  (message,  code,  timestamp)
VALUES  (?,  ?,  CURRENT_TIMESTAMP),  (?,  ?,  CURRENT_TIMESTAMP),
(?,  ?,  CURRENT_TIMESTAMP),  (?,  ?,  CURRENT_TIMESTAMP)
RETURNING  id,  message,  code,  timestamp
[...  (insertmanyvalues)  1/1  (unordered)]  ('log message #1',  'SQLA',  'log message #2',
'SQLA',  'log message #3',  'SQLA',  'log message #4',  'SQLA')
>>> print(log_record_result.all())
[LogRecord('log message #1', 'SQLA', datetime.datetime(...)),
 LogRecord('log message #2', 'SQLA', datetime.datetime(...)),
 LogRecord('log message #3', 'SQLA', datetime.datetime(...)),
 LogRecord('log message #4', 'SQLA', datetime.datetime(...))]
使用每行 SQL 表达式进行 ORM 批量插入

Insert.values()方法本身直接接受参数字典列表。当以这种方式使用Insert构造时,如果没有将参数字典列表传递给Session.execute.params参数,则不使用批量  ORM 插入模式,而是将 INSERT 语句完全按照给定的方式呈现并且仅调用一次。这种操作模式既对于逐行传递 SQL  表达式的情况有用,也适用于使用 ORM 的“upsert”语句时,本章后面的文档中有介绍,位于 ORM “upsert” Statements。

下面是一个构造性的示例,其中嵌入了每行 SQL 表达式的 INSERT,还以这种形式演示了Insert.returning()

>>> from sqlalchemy import select
>>> address_result = session.scalars(
...     insert(Address)
...     .values(
...         [
...             {
...                 "user_id": select(User.id).where(User.name == "sandy"),
...                 "email_address": "sandy@company.com",
...             },
...             {
...                 "user_id": select(User.id).where(User.name == "spongebob"),
...                 "email_address": "spongebob@company.com",
...             },
...             {
...                 "user_id": select(User.id).where(User.name == "patrick"),
...                 "email_address": "patrick@company.com",
...             },
...         ]
...     )
...     .returning(Address),
... )
INSERT  INTO  address  (user_id,  email_address)  VALUES
((SELECT  user_account.id
FROM  user_account
WHERE  user_account.name  =  ?),  ?),  ((SELECT  user_account.id
FROM  user_account
WHERE  user_account.name  =  ?),  ?),  ((SELECT  user_account.id
FROM  user_account
WHERE  user_account.name  =  ?),  ?)  RETURNING  id,  user_id,  email_address
[...]  ('sandy',  'sandy@company.com',  'spongebob',  'spongebob@company.com',
'patrick',  'patrick@company.com')
>>> print(address_result.all())
[Address(email_address='sandy@company.com'),
 Address(email_address='spongebob@company.com'),
 Address(email_address='patrick@company.com')]

因为上面没有使用批量 ORM 插入模式,所以下面的功能不可用:

  • 不支持联接表继承或其他多表映射,因为这将需要多个 INSERT 语句。
  • 不支持异构参数集 - VALUES 集合中的每个元素必须具有相同的列。
  • 不提供核心级别的规模优化,例如 insertmanyvalues 提供的批处理; 语句需要确保参数的总数不超过后端数据库施加的限制。

由于上述原因,通常不建议在 ORM INSERT 语句中使用Insert.values()与多个参数集合,除非有明确的理由,即要么使用了“upsert”,要么需要在每个参数集合中嵌入每行 SQL 表达式。

另请参阅

ORM “upsert” Statements ### Legacy Session Bulk INSERT Methods

Session包括用于执行“批量”INSERT 和 UPDATE 语句的传统方法。 这些方法与  SQLAlchemy 2.0 版本的这些功能共享实现,描述在 ORM 批量 INSERT 语句和 ORM 按主键批量  UPDATE,但缺少许多功能,即不支持 RETURNING 支持以及不支持会话同步。

使用Session.bulk_insert_mappings() 的代码,例如可以像下面这样移植代码,从这个映射示例开始:

session.bulk_insert_mappings(User, [{"name": "u1"}, {"name": "u2"}, {"name": "u3"}])

以上内容可使用新 API 表达为:

from sqlalchemy import insert
session.execute(insert(User), [{"name": "u1"}, {"name": "u2"}, {"name": "u3"}])

另请参阅

传统会话批量更新方法 ### ORM “upsert” 语句

在 SQLAlchemy 中,选定的后端可能包括特定方言的Insert 构造,这些构造还具有执行“upserts”或将参数集中的现有行转换为近似 UPDATE 语句的能力。对于“现有行”,这可能意味着共享相同主键值的行,或者可能是指被视为唯一的行内其他索引列;这取决于正在使用的后端的能力。

SQLAlchemy 包含有包含特定方言的“upsert” API 特性的方言,它们是:

  • SQLite - 使用Insert,文档位于 INSERT…ON CONFLICT(Upsert)
  • PostgreSQL - 使用Insert,文档位于 INSERT…ON CONFLICT(Upsert)
  • MySQL/MariaDB - 使用Insert,文档位于 INSERT…ON DUPLICATE KEY UPDATE(Upsert)

用户应该查阅上述章节以了解正确构建这些对象的背景;特别是,“upsert” 方法通常需要参考原始语句,因此通常语句会分为两个独立的步骤构建。

第三方后端,如在 外部方言 中提到的后端,也可能具有类似的构造。

虽然 SQLAlchemy 还没有与后端无关的 upsert 构造,但上述的 Insert 变体仍然与 ORM 兼容,因为它们可以像在 ORM Bulk Insert with Per Row SQL Expressions 中所记录的那样使用与 Insert 构造本身相同的方式,即通过在 Insert.values() 方法中嵌入要插入的所需行。在下面的例子中,使用 SQLite 的 insert() 函数来生成包含 “ON CONFLICT DO UPDATE” 支持的 Insert 构造。然后,将语句传递给 Session.execute(),它会正常进行,但额外的特点是传递给 Insert.values() 的参数字典被解释为 ORM 映射的属性键,而不是列名:

>>> from sqlalchemy.dialects.sqlite import insert as sqlite_upsert
>>> stmt = sqlite_upsert(User).values(
...     [
...         {"name": "spongebob", "fullname": "Spongebob Squarepants"},
...         {"name": "sandy", "fullname": "Sandy Cheeks"},
...         {"name": "patrick", "fullname": "Patrick Star"},
...         {"name": "squidward", "fullname": "Squidward Tentacles"},
...         {"name": "ehkrabs", "fullname": "Eugene H. Krabs"},
...     ]
... )
>>> stmt = stmt.on_conflict_do_update(
...     index_elements=[User.name], set_=dict(fullname=stmt.excluded.fullname)
... )
>>> session.execute(stmt)
INSERT  INTO  user_account  (name,  fullname)
VALUES  (?,  ?),  (?,  ?),  (?,  ?),  (?,  ?),  (?,  ?)
ON  CONFLICT  (name)  DO  UPDATE  SET  fullname  =  excluded.fullname
[...]  ('spongebob',  'Spongebob Squarepants',  'sandy',  'Sandy Cheeks',
'patrick',  'Patrick Star',  'squidward',  'Squidward Tentacles',
'ehkrabs',  'Eugene H. Krabs')
<...>
使用 RETURNING 与 upsert 语句

从 SQLAlchemy ORM 的角度来看,upsert 语句看起来就像普通的 Insert 构造,其中包括 Insert.returning() 与 upsert 语句的使用方式与在 ORM Bulk Insert with Per Row SQL Expressions 中演示的方式相同,因此可以传递任何列表达式或相关的 ORM 实体类。接着上一节的例子继续:

>>> result = session.scalars(
...     stmt.returning(User), execution_options={"populate_existing": True}
... )
INSERT  INTO  user_account  (name,  fullname)
VALUES  (?,  ?),  (?,  ?),  (?,  ?),  (?,  ?),  (?,  ?)
ON  CONFLICT  (name)  DO  UPDATE  SET  fullname  =  excluded.fullname
RETURNING  id,  name,  fullname,  species
[...]  ('spongebob',  'Spongebob Squarepants',  'sandy',  'Sandy Cheeks',
'patrick',  'Patrick Star',  'squidward',  'Squidward Tentacles',
'ehkrabs',  'Eugene H. Krabs')
>>> print(result.all())
[User(name='spongebob', fullname='Spongebob Squarepants'),
 User(name='sandy', fullname='Sandy Cheeks'),
 User(name='patrick', fullname='Patrick Star'),
 User(name='squidward', fullname='Squidward Tentacles'),
 User(name='ehkrabs', fullname='Eugene H. Krabs')]

上述示例使用 RETURNING 来返回由语句插入或更新的每一行的 ORM 对象。该示例还添加了 现有数据填充 执行选项的使用。此选项表示 Session 中已经存在的 User 对象应该使用新行的数据进行刷新。对于纯 Insert 语句来说,此选项并不重要,因为生成的每一行都是全新的主键标识。但是,当 Insert 还包括“upsert”选项时,它也可能会产生来自已经存在的行的结果,因此可能已经在 Session 对象的标识映射中具有主键标识。

另请参阅

现有数据填充 ## 按主键进行 ORM 批量更新

Update 构造可以与 Session.execute() 以类似的方式使用,就像 ORM 批量插入语句中描述的使用 Insert 语句一样,传递一个参数字典列表,每个字典表示对应单个主键值的单个行。这种用法不应与在 ORM 中更常见的使用 Update 语句的方式混淆,该方式使用显式的 WHERE 子句,在 ORM UPDATE and DELETE with Custom WHERE Criteria 中有文档记录。

对于“批量”版本的 UPDATE,通过 ORM 类构造一个update()语句,并传递给Session.execute()方法;生成的Update对象不应具有任何值,通常也不应具有 WHERE 条件,也就是说,不使用Update.values()方法,通常也不使用Update.where()方法,但在不寻常的情况下可能会使用,以添加额外的过滤条件。

Update构造与包含完整主键值的参数字典列表一起传递将触发主键批量 UPDATE 模式,生成适当的 WHERE 条件以按主键匹配每一行,并使用 executemany 对 UPDATE 语句运行每个参数集:

>>> from sqlalchemy import update
>>> session.execute(
...     update(User),
...     [
...         {"id": 1, "fullname": "Spongebob Squarepants"},
...         {"id": 3, "fullname": "Patrick Star"},
...         {"id": 5, "fullname": "Eugene H. Krabs"},
...     ],
... )
UPDATE  user_account  SET  fullname=?  WHERE  user_account.id  =  ?
[...]  [('Spongebob Squarepants',  1),  ('Patrick Star',  3),  ('Eugene H. Krabs',  5)]
<...>

请注意,每个参数字典必须为每个记录包含完整的主键,否则将引发错误。

与批量 INSERT 功能类似,这里也支持异构参数列表,其中参数将被分组为 UPDATE 运行的子批次。

在 2.0.11 版本中更改:可以使用Update.where()方法将附加的 WHERE 条件与 ORM 主键批量 UPDATE 组合使用以添加额外的条件。但是,此条件始终是附加到已经存在的包括主键值在内的 WHERE 条件之上的。

当使用“主键批量 UPDATE”功能时,不支持 RETURNING 功能;多个参数字典的列表必然使用了 DBAPI executemany,通常情况下,这种形式不支持结果行。

在 2.0 版中更改:将 Update 结构传递给 Session.execute() 方法以及参数字典列表现在调用“批量更新”,这使用的是与旧版 Session.bulk_update_mappings() 方法相同的功能。这与 1.x 系列中的行为更改不同,在 1.x 系列中,Update 仅受到显式 WHERE 条件和内联 VALUES 的支持。


SqlAlchemy 2.0 中文文档(十七)(2)https://developer.aliyun.com/article/1562953

相关文章
|
3月前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(十七)(2)
SqlAlchemy 2.0 中文文档(十七)
33 4
|
3月前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(十七)(3)
SqlAlchemy 2.0 中文文档(十七)
34 4
|
3月前
|
SQL 关系型数据库 API
SqlAlchemy 2.0 中文文档(十七)(4)
SqlAlchemy 2.0 中文文档(十七)
53 4
|
3月前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(十七)(5)
SqlAlchemy 2.0 中文文档(十七)
25 1
|
3月前
|
SQL 测试技术 数据库
SqlAlchemy 2.0 中文文档(十二)(5)
SqlAlchemy 2.0 中文文档(十二)
21 2
|
3月前
|
SQL 缓存 数据库连接
SqlAlchemy 2.0 中文文档(二十二)(3)
SqlAlchemy 2.0 中文文档(二十二)
19 5
|
3月前
|
SQL Python
SqlAlchemy 2.0 中文文档(十五)(5)
SqlAlchemy 2.0 中文文档(十五)
67 1
|
3月前
|
SQL 测试技术 API
SqlAlchemy 2.0 中文文档(十五)(2)
SqlAlchemy 2.0 中文文档(十五)
73 1
|
3月前
|
SQL Oracle 关系型数据库
SqlAlchemy 2.0 中文文档(十五)(1)
SqlAlchemy 2.0 中文文档(十五)
39 1
|
3月前
|
SQL 测试技术 知识图谱
SqlAlchemy 2.0 中文文档(十五)(4)
SqlAlchemy 2.0 中文文档(十五)
34 1
下一篇
无影云桌面