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

如果条目不存在,则使用PostgreSQL进行多个插入,sql,postgresql,common-table-expression,sql-insert,Sql,Postgresql,Common Table Expression,Sql Insert,如果条目不存在,我想将数据插入多个表中 在我的例子中,我有一个餐厅表、一个位置表、一个foodtype表和一些助手表,如restaurant\u location、和restaurant\u foodtype。现在,我想插入一个新的餐馆条目,如果条目不存在,则包含位置和foodtype信息 比如: IF NOT (select 1 from restaurant where name='restaurantname') THEN INSERT INTO restaurant(x,y) VALU

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

在我的例子中,我有一个餐厅表、一个位置表、一个
foodtype
表和一些助手表,如
restaurant\u location
、和
restaurant\u foodtype
。现在,我想插入一个新的餐馆条目,如果条目不存在,则包含位置和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,这应该是我的想法

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)

在Postgres9.1或更高版本中您可以使用它来实现快速、安全、简单和优雅:

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”时,才会执行第一次插入。如果多个查询在同一实例中尝试相同的查询,则存在一个极小的竞争条件。如果您对
restaurant.name
UNIQUE
约束(就像您应该从描述中判断的那样),最糟糕的情况是,在并发查询中,只有第一个查询会成功,而其他查询返回时会出现唯一的违规(不执行任何操作)。然而,你可能永远也看不到这一点,因为这不太可能发生

RETURNING
子句返回自动生成的
rest\u id
——我假设
rest\u id
是一个串行列

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

用一个简单的
插入来完成本系列

使用PostgreSQL 8.1,我将编写一个plpgsql函数来实现同样的功能。

但是,实际上,您最好升级到。

这对于一条insert语句非常有效。但我有多个。仅仅将WHERE NOT EXISTS添加到每一个INSERT中是不起作用的,因为在第一次INSERT之后,条目应该存在。如果第一行餐厅不存在,那么您将插入一行。那家餐馆的身份证号码可以通过电话查询。您不需要检查相关插入是否存在id号;外键约束保证它不可能存在,除非您的数据库设计被严重破坏。没有“简单”的SQL查询插入到多个表中。但是它很容易在plpgsql的过程代码中完成,这看起来很像问题中的伪代码。如果你因为某种原因不能使用它,欢迎提供更多关于上下文的信息。8.1已经很长时间不受支持了。您现在应该升级了,真的。@DanielVérité:好吧,因为Postgres 9.1可以使用“简单”的SQL语句,使用数据修改CTE来完成升级。我发布了一个示例。这基本上就是我在要求版本时的想法;)这是“快速、安全、简单、优雅”吗?我只是在一个项目中使用postGreSQL,我想知道这是否真的是执行此注释操作的最简单方法。如果将其包装在一个返回复合数据类型的函数中,则如果存在,将返回一个空行(而不是无行)。为什么?