sql - 如果条目不存在,则使用 PostgreSQL 进行多次插入

标签 sql postgresql common-table-expression sql-insert

如果条目不存在,我想将数据插入到多个表中。

在我的示例中,我有一个餐厅表、一个位置表、一个foodtype 表和一些辅助表,例如restaurant_locationrestaurant_foodtype。现在,如果该条目不存在,我想插入一个包含位置和食物类型信息的新餐厅条目。

所以像这样:

IF NOT (select 1 from restaurant where name='restaurantname') THEN
 INSERT INTO restaurant(x,y) VALUES (valuex,valuey);
 INSERT INTO restaurant_location(rest_id,..) VALUES (rest_id,..);
 INSERT INTO restaurant_foodtype(rest_id,..) VALUES (rest_id,..);
 ...
END IF

如何使用简单的 SQL 执行此操作?

最佳答案

在 Postgres 9.1 或更高版本 中,您可以使用 data-modifying CTEs使其快速、安全、简单和优雅:

WITH x AS (
   INSERT INTO restaurant(name, x, y)
   SELECT 'restaurantname', valuex, valuey
   WHERE  NOT EXISTS (SELECT 1 FROM restaurant WHERE name = 'restaurantname')
   RETURNING rest_id     -- returns auto-generated id (from sequence)
   )
, y AS (
   INSERT INTO restaurant_location(rest_id, ...)
   SELECT rest_id, ...
   FROM   x              -- only produces rows after a successful INSERT
   )

   --- more chained INSERTs here?

INSERT INTO restaurant_foodtype(rest_id, ...)
SELECT rest_id, ...
FROM   x;

第一个 INSERT 仅在未找到“restaurantname”时执行。如果多个查询应在同一实例中尝试相同的查询,则会出现超小的竞争条件。如果您对 restaurant.name 有一个 UNIQUE 约束(就像您应该从您的描述中判断的那样),可能发生的最坏情况是在并发查询中只有第一个会成功,而其他人以独特的违规行为返回(什么都不做)。然而,您很可能永远不会看到这种情况,因为它不太可能发生。

RETURNING 子句返回自动生成的 rest_id - 我假设 rest_id 是一个序列列。

以下 INSERT 查询仅在第一个成功时生成行。

以简单的 INSERT 结束本系列。

对于 PostgreSQL 8.1,我会编写一个 plpgsql 函数来实现相同的目的。
但是,真的,你最好升级到 current version .

关于sql - 如果条目不存在,则使用 PostgreSQL 进行多次插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12157805/

相关文章:

sql - 如何在 postgresql 中返回日期值?

common-table-expression - 带有多个删除语句的 SQL Server CTE

sql - 简化 WHERE (NOT) IN (...) 和 WHERE (NOT) IN (...)

sql - SQL Server 2005 中 CTE 的评估

python - 使用全栈 Python 应用程序打包数据库

mysql - 连接 3 个包含空值的表

php - 数据库设计选择

sql - 如何在同一个 SELECT 语句中使用 DISTINCT 和 ORDER BY?

postgresql - Plpgsql 错误 : missing FROM-clause entry for table when trying to insert

sql - PostgreSQL : How to select values with only two digits after decimal point in a table?