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

Posted

技术标签:

【中文标题】如果条目不存在,则使用 PostgreSQL 进行多次插入【英文标题】:Multiple Inserts with PostgreSQL if an entry does not exist 【发布时间】:2012-08-28 10:56:51 【问题描述】:

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

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

【问题讨论】:

没有插入多个表的“简单”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 进行多次插入的主要内容,如果未能解决你的问题,请参考以下文章

如果条目存在和不存在,则返回列表

如果不存在则插入行 postgresql

HSQLDB -Query - 如果不存在则插入第一条记录

postgresql:如果不退出则创建用户[重复]

jQuery Tokeninput 如果不存在则添加

如果图像不存在,则 cakephp 占位符