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

Ste*_*Arn 3 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
Run Code Online (Sandbox Code Playgroud)

我怎么能用简单的SQL做到这一点?

Erw*_*ter 9

在Postgres 9.1或更高版本中,您可以使用数据修改CTE来实现快速,安全,简单和优雅:

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;
Run Code Online (Sandbox Code Playgroud)

第一个INSERT仅在未找到'restaurantname'时执行.如果多个查询在同一个实例中尝试相同,则存在超小的竞争条件.如果你有一个UNIQUE约束restaurant.name(就像你应该从你的描述判断),可能发生的最坏情况是,在同意的查询中,只有第一个会成功,而其他人会以唯一的违规行为(无所事事)返回.但是,你很可能永远不会看到这一点,因为它不太可能发生.

RETURNING子句返回自动生成的rest_id- 我假设rest_id是一个串行列.

INSERT如果第一个查询成功,则以下查询仅生成行.

完成系列是一个平原INSERT.

使用PostgreSQL 8.1我会编写一个plpgsql函数来实现相同的功能.
但是,实际上,您最好升级到当前版本.