sql >> データベース >  >> RDS >> PostgreSQL

更新せずに、ONCONFLICTを使用してINSERTから行を返します

    これは、 SELECT or INSERTの繰り返しの問題です。 、UPSERTに関連しています(ただし、UPSERTとは異なります)。 Postgres9.5の新しいUPSERT機能は引き続き機能します。

    WITH ins AS (
       INSERT INTO names(name)
       VALUES ('bob')
       ON     CONFLICT ON CONSTRAINT names_name_key DO UPDATE
       SET    name = NULL
       WHERE  FALSE      -- never executed, but locks the row
       RETURNING id
       )
    SELECT id FROM ins
    UNION  ALL
    SELECT id FROM names
    WHERE  name = 'bob'  -- only executed if no INSERT
    LIMIT  1;
    

    このようにして、実際に新しい行バージョンを作成する必要はありません。

    ただし競合状態の小さなコーナーケースはまだあります 。並行トランザクションにより、競合する行が追加された可能性がありますが、同じステートメントにはまだ表示されていません。次に、INSERT および SELECT 空になります。

    単列UPSERTの適切なソリューション:

    • 関数内のSELECTまたはINSERTは競合状態になりやすいですか?

    バルクUPSERTの一般的なソリューション:

    • PostgreSQLでONCONFLICTを使用してRETURNINGを使用するにはどうすればよいですか?

    同時書き込み負荷なし

    (別のセッションからの)同時書き込みが不可能な場合は、行をロックする必要はなく、単純化できます:

    WITH ins AS (
       INSERT INTO names(name)
       VALUES ('bob')
       ON     CONFLICT ON CONSTRAINT names_name_key DO NOTHING  -- no lock needed
       RETURNING id
       )
    SELECT id FROM ins
    UNION  ALL
    SELECT id FROM names
    WHERE  name = 'bob'  -- only executed if no INSERT
    LIMIT  1;
    



    1. INSERTINTOとSELECTINTO

    2. SQL Server(T-SQL)で文字列の左側の部分を取得する

    3. SQLServerでネストされたcaseステートメントロジックを実行するための最良の方法

    4. PostgreSQLのカスタムトリガーベースのアップグレード