使用 INSERT 语句¶
当使用 Core 以及使用 ORM 进行批量作时,使用 insert()
函数直接生成 SQL INSERT 语句 - 此函数生成一个新的 Insert
实例,该实例表示 SQL 中的 INSERT 语句,将新数据添加到表中。
ORM 阅读器 -
本节详细介绍了生成单个 SQL INSERT 的核心方法
语句,以便向表中添加新行。使用 ORM 时,我们
通常使用另一个位于此之上的工具,称为
work 单元,它将一次自动生成多个 INSERT 语句。然而,即使 ORM 为我们运行数据,了解 Core 如何处理数据的创建和作也非常有用。此外,ORM 支持使用称为 Bulk / Multi Row INSERT、upsert、UPDATE 和 DELETE 的功能直接使用 INSERT。
要直接跳到如何使用常规工作单元模式通过 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'}
执行语句¶
调用该语句,我们可以在 user_table
中 INSERT 一行。在 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 语句不返回任何行,如果只插入一行,它通常包括返回有关在该行的 INSERT 期间生成的列级默认值的信息的能力,最常见的是整数主键值。在上述情况下,SQLite 数据库中的第一行通常会返回 1
第一个整数主键值,我们可以使用
CursorResult.inserted_primary_key
访问:
>>> result.inserted_primary_key
(1,)
提示
CursorResult.inserted_primary_key
返回一个元组,因为一个主键可能包含多个列。这称为复合主键。这 CursorResult.inserted_primary_key
旨在始终包含记录的完整主键
inserted,而不仅仅是 “cursor.lastrowId” 类型的值,并且还打算
无论是否使用 “autoincrement” 进行填充,因此
要表示完整的主键,它是一个 Tuples。
在 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()
调用并执行它而不是打印它,该语句将根据我们传递给 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 子句中表示
自动构造。
深度炼金术
嗨,欢迎来到 Deep Alchemy 的第一版。左边的人被称为炼金术士,你会注意到他们不是巫师,因为尖帽没有向上伸。炼金术士来描述通常更高级和/或更棘手的事情,而且通常不需要,但无论出于何种原因,他们认为您应该了解 SQLAlchemy 可以做的这件事。
在这个版本中,朝着在
address_table
,下面是一个更高级的示例,说明了如何显式使用 Insert.values()
方法,同时包括从参数生成的其他 VALUES。构建一个标量子查询,利用
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
这样,我们的表格中有一些更有趣的数据,我们将在接下来的部分中使用这些数据。
提示
一个真正的 “空” INSERT,它只插入表的 “defaults”
不包含任何显式值,如果我们指示
Insert.values()
没有参数;并非每个数据库后端都支持此功能,但这是 SQLite 产生的:
>>> print(insert(user_table).values().compile(engine))
INSERT INTO user_account DEFAULT VALUES
插入。。。返回¶
支持的后端的 RETURNING 子句会自动用于检索最后插入的主键值以及服务器默认值的值。但是,也可以使用 Insert.returning()
显式指定 RETURNING 子句
方法;在本例中,Result
执行语句时返回的对象包含的 rows
可以获取:
>>> 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 语句也支持 RETURNING 功能,本教程稍后将介绍这些功能。
对于 INSERT 语句,可以使用 RETURNING 功能
对于单行语句以及 INSERT 的语句
一次多行。 支持带 RETURN 的多行 INSERT
特定于方言,但支持所有方言
包含在支持 RETURNING 的 SQLAlchemy 中。 请参阅该部分
INSERT 语句的 “Insert Many Values” 行为,了解此功能的背景信息。
另请参阅
ORM 还支持带或不带 RETURNING 的批量 INSERT。 看
ORM Bulk INSERT 语句,用于参考文档。
插入。。。从 SELECT 开始¶
Insert
的一个较少使用的功能,但为了完整起见,
Insert
结构可以编写一个 INSERT,该 INSERT 使用 Insert.from_select()
方法直接从 SELECT 获取行。此方法接受 select()
结构,这将在下一节中讨论,以及要在实际 INSERT 中针对的列名列表。在下面的示例中,行被添加到地址
表,这些地址派生自 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
当想要将数据从数据库的其他部分直接复制到一组新的行中,而不实际从 Client 端获取和重新发送数据时,会使用此结构。
另请参阅
Insert
- 在 SQL Expression API 文档中