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

时间:2012-08-28 10:56:51

标签: 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执行此操作?

2 个答案:

答案 0 :(得分:7)

在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;

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

RETURNING子句返回自动生成的rest_id - 我认为rest_id是一个串行列。

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

使用普通INSERT完成系列。

使用PostgreSQL 8.1我会编写一个plpgsql函数来实现相同的目标 但是,实际上,您最好升级到current version

答案 1 :(得分:1)

我只是把它写在了我的头脑中,但这应该是想法,如果你必须用简单的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)