如果条目不存在,则使用 PostgreSQL 进行多次插入
Posted
技术标签:
【中文标题】如果条目不存在,则使用 PostgreSQL 进行多次插入【英文标题】:Multiple Inserts with PostgreSQL if an entry does not exist 【发布时间】:2012-08-28 10:56:51 【问题描述】:如果条目不存在,我想将数据插入到多个表中。
就我而言,我有一张餐厅桌、一张位置桌、一张foodtype
桌和一些辅助桌,例如restaurant_location
和restaurant_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 来做到这一点?
【问题讨论】:
没有插入多个表的“简单”SQL 查询。但它很容易在 plpgsql 中的过程代码中完成,这看起来很像问题中的伪代码。如果由于某种原因您不能使用它,欢迎提供有关上下文的更多信息。 8.1 已经不支持很久了。你应该现在升级,真的。 @DanielVérité:嗯,从 Postgres 9.1 开始,它可以通过使用数据修改 CTE 的“简单”SQL 语句来完成。我发布了一个例子。 【参考方案1】:在 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。
【讨论】:
这基本上是我在询问版本时的想法;) 这是“快速、安全、简单、优雅”吗?我只是在一个项目中使用 postGreSQL,我想知道这是否真的是执行此评论操作的最简单方法。 如果将其包装在返回复合数据类型的函数中,如果存在则返回空行(而不是无行)。为什么? ***.com/questions/22700215/…【参考方案2】:我只是在脑海中写了这个,但如果你必须用简单的 sql 来做的话,应该是这个想法。
insert into
restaurant(x, y)
values
select valuex, valuey
from dual
where
not exists(
select 1 from restaurant where name = 'restaurantname')
编辑: 同样,我无法解析它,但您可能可以使用 WITH 子句:
with validation as(
select 1 from restaurant where name = 'restaurantname'
)
insert into
restaurant(x, y)
values
(
select value1x, value1y
from dual
where
validation.v = 1),
(
select value2x, value2y
from dual
where
validation.v = 1)
【讨论】:
这适用于一个插入语句。但我有多个。只是将 WHERE NOT EXISTS 添加到每个 INSERT 是行不通的,因为在第一次插入后,条目应该存在 如果第一行的餐厅不存在,您将插入一行。 那家餐厅的身份证号码可通过currval() function 访问。您无需检查相关插入是否存在 id 号;外键约束保证它不可能存在,除非你的数据库设计被严重破坏。以上是关于如果条目不存在,则使用 PostgreSQL 进行多次插入的主要内容,如果未能解决你的问题,请参考以下文章