2013-04-20 16 views
6

色Xと明度Yのユーザーを探すというPostgres SQL文を1つ書く必要があります。そのユーザーが存在する場合は、すべての行データを返します。そうでない場合は、新しい行を作成し、追加情報を渡します。二つの別々のステートメントは、このようなものだろう:それは何も返さない場合Postgresの作成SQLクエリの取得または作成

Select (color, brightness, size, age) FROM mytable WHERE color = 'X' AND brightness= 'Y'; 

を、これを実行します。

INSERT INTO mytable (color, brightness, size, age) VALUES (X, Y, big, old); 

単一のクエリにこれらを結合する方法はあります? SQL DBMSで

+0

INSERT文でpostgresqlの 'RETURNING'節の拡張を見ると、私は当初、unionを使ってinsertとselectをselect文と組み合わせることができましたが、試してみましたが、残念ながら読み書きは実際には不可能ですそうですね。 – didierc

答えて

15

、選択テスト・インサート・アプローチは間違いです:何があなたのselectinsert文の間の「行方不明」の行を挿入し、別のプロセスを妨げません。これを代わりに実行してください:

insert into mytable (color, brightness, size, age) 
select (color, brightness, size, age) from mytable 
where not exists (
    select 1 from 
    from mytable 
    where color = 'X' and brightness = 'Y' 
); 
SELECT (color, brightness, size, age) 
FROM mytable 
WHERE color = 'X' AND brightness= 'Y'; 

このテキスト全体を単一の「クエリ」としてDBMSに渡すことができます。ストアドプロシージャにすることを検討することをお勧めします。 (あなたがcolorに一意のインデックスを持っていると仮定)

INSERT INTO mytable (color, brightness, size, age) 
VALUES ('X', 'Y', 'big', 'old') 
ON CONFLICT (color) DO NOTHING; 

:あなたの列が一意インデックス制約に参加した場合

+0

この回答に関連すると便利です。http://stackoverflow.com/a/13342031/399726 – BenjaminGolder

+0

この回答が構文エラーを含む多数の投票を収集した方法を理解できません。 PostgresのINSERTにはオプション 'insert ... where ...'はありません。おそらく 'mytable(色、明度、サイズ、年齢)に挿入することを意味するSELECT 'X'、 'Y'、1.2,3.4は存在しません。 – greatvovan

4
with sel as (
    select color, brightness, size, age 
    from mytable 
    where color = 'X' and brightness = 'Y' 
), ins as (
    insert into mytable (color, brightness, size, age) 
    select 'X', 'Y', 6.2, 40 
    where not exists (
     select 1 from sel 
    ) 
    returning color, brightness, size, age 
) 
select color, brightness, size, age 
from ins 
union 
select color, brightness, size, age 
from sel 
2

あなたは、バージョン9.5以降のavaibleあるアプローチを使用することができます。

ドキュメントは・ギアです:https://www.postgresql.org/docs/9.5/static/sql-insert.html

+0

これは質問に答えるものではありません。これは、行を取得する*または*作成する*方法を尋ねます。 – Druska

1

は、ここに私の解決策を追加します。これは、@Clodoaldo Netoと@ astefのソリューションとは異なるものです。

WITH ins AS (
    INSERT INTO mytable (color, brightness, size, age) 
    VALUES ('X', 'Y', 'big', 'old') 
    ON CONFLICT (color) DO NOTHING 
    RETURNING * 
) 
SELECT * FROM ins 
UNION 
SELECT * FROM mytable 
    WHERE color = 'X'; 

私は自分の目的のためにastefの解決策が不十分が見つかりました:それは、「取得または作成」の「取得」の部分を実行しません!値がすでに存在する場合、何も起こりません。

文の最後にある共用体は、値が挿入されていない(すでに存在しているため)場合でも、その値をテーブルから取得します。

+0

上記の問題が見つかりました。競合が発生した場合、クエリの実行ごとにテーブルのシリアルIDカウンタが増加します。これは理想的ではありません。 –

関連する問題