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

最後に挿入されたIDのPostgreSQL関数

    tl;dr :gotoオプション3:INSERT with RETURNING)

    postgresqlには、テーブルの「id」の概念はなく、シーケンスだけであることを思い出してください。 (これは通常、SERIAL疑似タイプで、代理主キーのデフォルト値として使用されますが、必ずしもそうとは限りません)。

    新しく挿入された行のIDを取得することに関心がある場合は、いくつかの方法があります。

    オプション1:CURRVAL(<sequence name>);

    例:

      INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
      SELECT currval('persons_id_seq');
    

    シーケンスの名前は既知である必要があります。これは実際には任意です。この例では、テーブルpersonsを想定しています。 idがあります SERIALで作成された列 疑似タイプ。これに依存することを避け、よりクリーンに感じるために、代わりにpg_get_serial_sequenceを使用できます。 :

      INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
      SELECT currval(pg_get_serial_sequence('persons','id'));
    

    警告:currval() INSERTの後にのみ機能します (nextval()を実行しました )、同じセッションで

    オプション2:LASTVAL();

    これは前の例と似ていますが、シーケンス名を指定する必要がない点が異なります。最新の変更されたシーケンスを検索します(常にセッション内で、上記と同じ注意事項)。

    両方のCURRVAL およびLASTVAL 完全に同時安全です。 PGでのシーケンスの動作は、異なるセッションが干渉しないように設計されているため、競合状態のリスクはありません(別のセッションがINSERTとSELECTの間に別の行を挿入しても、正しい値を取得します)。

    ただし 彼らには微妙な潜在的な問題があります。データベースにトリガー(またはルール)がある場合は、personsに挿入します。 テーブル、他のテーブルにいくつかの追加の挿入を行います...次にLASTVAL おそらく間違った値を与えるでしょう。この問題は、CURRVALでも発生する可能性があります 、同じpersonsに追加の挿入が行われた場合 テーブル(これはあまり一般的ではありませんが、リスクは依然として存在します)。

    オプション3:INSERT RETURNINGを使用

    INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
    

    これは、IDを取得するための最もクリーンで効率的かつ安全な方法です。以前のようなリスクはありません。

    欠点?ほとんどありません。INSERTステートメントの呼び出し方法を変更する必要がある場合があります(最悪の場合、APIまたはDBレイヤーはINSERTが値を返すことを期待していません)。これは標準のSQLではありません(誰が気にしますか)。 Postgresql 8.2(2006年12月...)から利用可能です

    結論:可能であれば、オプション3を選択してください。それ以外の場合は、1を選択してください。

    注:最後に挿入されたIDをグローバルに取得する場合、これらのメソッドはすべて役に立ちません。 (必ずしもセッションによってではありません)。このためには、SELECT max(id) FROM tableに頼る必要があります (もちろん、これは他のトランザクションからのコミットされていない挿入を読み取りません)。

    逆に、絶対にしないでください SELECT max(id) FROM tableを使用します 代わりに、上記の3つのオプションのいずれかを使用して、INSERTによって生成されたIDを取得します。 ステートメント、(パフォーマンスは別として)これは同時安全ではないため:INSERTの間 およびSELECT 別のセッションが別のレコードを挿入した可能性があります。



    1. SQL SELECT DISTINCT:パフォーマンスのベストプラクティス

    2. java.library.pathにsqljdbc_authがありません

    3. ToadForOracleでプロシージャを実行する方法を学ぶ

    4. SQL ServerでのROW_NUMBER()のしくみ