SQLAlchemy 2.0 文档
使用 INSERT 语句¶
当使用 Core 以及使用 ORM 进行批量操作时,SQL INSERT 语句直接使用 insert()
函数生成 - 此函数生成 Insert
的新实例,它表示 SQL 中的 INSERT 语句,用于向表中添加新数据。
ORM 阅读者 -
本节详细介绍了使用 Core 生成单个 SQL INSERT 语句以向表中添加新行的方法。当使用 ORM 时,我们通常使用另一个位于其之上的工具,称为 工作单元,它将自动生成许多 INSERT 语句。然而,即使 ORM 为我们运行它,了解 Core 如何处理数据创建和操作也是非常有用的。此外,ORM 支持直接使用 INSERT,使用一个名为 批量/多行 INSERT、upsert、UPDATE 和 DELETE 的功能。
要直接跳到如何使用 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
构造是“参数化”构造的一个示例,之前在 发送参数 中说明过;要查看 name
和 fullname
绑定参数,这些参数也可以从 Compiled
构造中获得
>>> compiled.params
{'name': 'spongebob', 'fullname': 'Spongebob Squarepants'}
执行语句¶
调用该语句,我们可以将一行 INSERT 到 user_table
中。INSERT SQL 以及捆绑的参数可以在 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 语句不返回任何行,如果只插入一行,它通常会包含返回有关在该行的 INSERT 期间生成的列级默认值的信息的能力,最常见的是整数主键值。在上面的示例中,SQLite 数据库中的第一行通常会为第一个整数主键值返回 1
,我们可以使用 CursorResult.inserted_primary_key
访问器获取该值
>>> result.inserted_primary_key
(1,)
提示
CursorResult.inserted_primary_key
返回一个元组,因为主键可能包含多个列。这被称为 复合主键。CursorResult.inserted_primary_key
旨在始终包含刚刚插入的记录的完整主键,而不仅仅是“cursor.lastrowid”类型的值,并且也旨在无论是否使用“autoincrement”都填充,因此为了表达完整的主键,它是一个元组。
在版本 1.4.8 中更改: 由 CursorResult.inserted_primary_key
返回的元组现在是一个命名元组,通过将其作为 Row
对象返回来实现。
INSERT 通常自动生成 “values” 子句¶
上面的示例使用了 Insert.values()
方法来显式创建 SQL INSERT 语句的 VALUES 子句。如果我们实际上不使用 Insert.values()
而只是打印一个“空”语句,我们将获得表中每一列的 INSERT
>>> print(insert(user_table))
INSERT INTO user_account (id, name, fullname) VALUES (:id, :name, :fullname)
如果我们采用一个尚未调用 Insert.values()
的 Insert
构造,并执行它而不是打印它,则该语句将根据我们传递给 Connection.execute()
方法的参数编译成字符串,并且仅包含与传递的参数相关的列。这实际上是使用 Insert
插入行的常用方法,而无需键入显式的 VALUES 子句。下面的示例说明了一个双列 INSERT 语句,它与参数列表一起执行
>>> 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
上面的执行以上述 发送多个参数 中首次说明的 “executemany” 形式为特色,但是与使用 text()
构造不同,我们不必拼写任何 SQL。通过将字典或字典列表传递给 Connection.execute()
方法,并结合 Insert
构造,Connection
确保传递的列名将自动在 Insert
构造的 VALUES 子句中表达。
深入炼金术
嗨,欢迎来到第一版 深入炼金术。左边的人被称为 炼金术士,你会注意到他们不是巫师,因为尖尖的帽子没有向上翘起。炼金术士出现是为了描述那些通常 更高级和/或棘手 并且 通常不需要 的事物,但无论出于何种原因,他们认为你应该了解 SQLAlchemy 可以做的这件事。
在本版中,为了在 address_table
中也有一些有趣的数据,下面是一个更高级的示例,说明如何显式使用 Insert.values()
方法,同时包含从参数生成的附加 VALUES。构造了一个 标量子查询,利用了下一节中介绍的 select()
构造,并且子查询中使用的参数是使用显式绑定参数名称设置的,该名称是使用 bindparam()
构造建立的。
这是一些稍微 深入 的炼金术,只是为了我们可以添加相关行,而无需从应用程序中的 user_table
操作中获取主键标识符。大多数炼金术士将简单地使用 ORM,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
有了这些,我们的表中有了一些更有趣的数据,我们将在接下来的章节中使用这些数据。
提示
如果我们在没有参数的情况下指示 Insert.values()
,则会生成一个真正的“空” INSERT,它仅插入表的“默认值”,而不包含任何显式值;并非每个数据库后端都支持此功能,但这是 SQLite 生成的内容
>>> print(insert(user_table).values().compile(engine))
INSERT INTO user_account DEFAULT VALUES
INSERT…RETURNING¶
对于受支持的后端,RETURNING 子句会自动用于检索最后插入的主键值以及服务器默认值的值。但是,也可以使用 Insert.returning()
方法显式指定 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()
结合使用,如下面的示例所示,该示例建立在 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.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 语句也支持 RETURNING 功能,这将在本教程的后面介绍。
对于 INSERT 语句,RETURNING 功能可以用于单行语句以及一次 INSERT 多行的语句。对带有 RETURNING 的多行 INSERT 的支持是方言特定的,但是 SQLAlchemy 中包含的所有支持 RETURNING 的方言都支持它。有关此功能的背景信息,请参阅 “INSERT 语句的“插入多个值”行为” 部分。
另请参阅
ORM 也支持带有或不带有 RETURNING 的批量 INSERT。有关参考文档,请参阅 ORM 批量 INSERT 语句。
INSERT…FROM SELECT¶
Insert
的一个较少使用的功能,但为了完整起见,Insert
构造可以组合一个 INSERT,该 INSERT 使用 Insert.from_select()
方法直接从 SELECT 获取行。此方法接受一个 select()
构造(将在下一节中讨论),以及要在实际 INSERT 中定位的列名列表。在下面的示例中,将行添加到 address
表,这些行派生自 user_account
表中的行,从而为每个用户提供一个在 aol.com
的免费电子邮件地址
>>> 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
- 在 SQL 表达式 API 文档中
flambé! 龙和 炼金术士 图像设计由 Rotem Yaari 创建并慷慨捐赠。
使用 Sphinx 7.2.6 创建。文档最后生成时间: 2025年3月11日 02:40:17 PM EDT