2012-08-28 20 views
3

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

在我的情况下,我有一张餐桌,一张位置表,一张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?

+0

哪个PostgreSQL版本? –

+0

我使用的PostgreSQL 8.1.3 –

+0

没有“简单”的SQL查询插入到多个表中。但它很容易在plpgsql的过程代码中完成,它看起来非常像问题中的伪代码。如果由于某种原因无法使用该功能,则欢迎有关上下文的更多信息。 –

回答

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) 
+0

这对于一个插入语句非常有用。但我有多个。只是将WHERE NOT EXISTS添加到每个INSERT都不起作用,导致第一次插入后,该条目应该存在 –

+1

如果餐厅不存在第一行,则会插入一行。*该餐厅的ID号可通过[currval()函数](http://www.postgresql.org/docs/9.1/static/functions-sequence.html)访问。你不需要检查相关的插入是否存在一个id号;外键约束保证它不可能存在,除非你的数据库设计被严重破坏。 –

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; 

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

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

以下INSERT查询只在第一个成功时才会生成行。

用简单的INSERT完成系列。

随着PostgreSQL 8.1我会写一个plpgsql函数来实现相同。
但是,真的,你最好升级到current version

+0

这就是我寻求版本时想到的基本原理;) –

+0

Tis是“快速,安全,简单,优雅”吗?我只是在一个项目中使用postGreSQL,我不得不怀疑这是否是真正实现这个评论操作的最简单方法。 – joelm

+0

如果将其封装在一个返回组合数据类型的函数中,则返回空行(而不是无行)(如果存在)。为什么? http://stackoverflow.com/questions/22700215/shouldnt-this-postgresql-function-return-zero-rows – ma11hew28

相关问题