2012-08-28 25 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

相關問題