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;

1 つ目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 に答える