3

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

就我而言,我有一张餐厅桌、一张位置桌、一张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 做到这一点?

4

2 回答 2

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;

第一个INSERT仅在未找到“restaurantname”时执行。如果多个查询应该在同一个实例中尝试相同的情况,则存在一个非常小的竞争条件。如果你有一个UNIQUE限制restaurant.name(就像你应该从你的描述中判断的那样),可能发生的最糟糕的情况是,在并发查询中,只有第一个会成功,而其他查询会返回一个唯一的违规(什么都不做)。但是,您可能永远不会看到这种情况,因为它不太可能发生。

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

以下INSERT查询仅在第一个成功的情况下生成行。

以朴素结束这个系列INSERT

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

于 2012-08-28T13:52:40.920 回答
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)
于 2012-08-28T11:01:41.367 回答