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

PL/pgSQLの列名は変数と同じ

    id_pracownikaを想定 PRIMARY KEYです テーブルの。または、少なくとも定義されたUNIQUE 。 (NOT NULLでない場合 、NULLはコーナーケースです。)

    SELECT またはINSERT

    あなたの関数は「SELECTまたはINSERT」の別の実装です-UPSERTの変形です 問題。これは、同時書き込みロードに直面すると、見た目よりも複雑になります。参照:

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

    Postgres9.5以降のUPSERTを使用

    Postgres 9.5以降では、UPSERT(INSERT ... ON CONFLICT ... )PostgresWikiの詳細。この新しい構文はクリーンな仕事を行います :

    CREATE OR REPLACE FUNCTION hire(
            _id_pracownika integer
          , _imie varchar
          , _nazwisko varchar
          , _miasto varchar
          , _pensja real)
      RETURNS text
      LANGUAGE plpgsql AS
    $func$
    BEGIN
       INSERT INTO pracownicy
              ( id_pracownika, imie, nazwisko, miasto, pensja)
       VALUES (_id_pracownika,_imie,_nazwisko,_miasto,_pensja);
       ON     CONFLICT DO NOTHING
       RETURNING 'OK';
    
       IF NOT FOUND THEN
          RETURN 'JUZ ISTNIEJE';
       END IF;
    END
    $func$;
    

    必要に応じて明確にするために、列名をテーブル修飾します。 (関数パラメーターの前に関数名を付けることもできますが、それは簡単に厄介になります。)
    ただし、INSERTのターゲットリストの列名 テーブル認定されていない可能性があります。 (とにかく曖昧にしないでください。)

    このようなあいまいさを事前に回避することをお勧めします。これにより、エラーが発生しにくくなります。一部の人(私を含む)は、すべての関数パラメーターと変数の前にアンダースコアを付けることでそれを行うのが好きです。

    積極的に必要の場合 関数パラメータ名としての列名も、名前の衝突を回避する1つの方法は、 ALIASを使用することです。 関数内。 ALIASが発生するまれなケースの1つ 実際に便利です。

    または、序数位置で関数パラメーターを参照します: $1 id_pracownikaの場合 この場合。

    他のすべてが失敗した場合は、#variable_conflictを設定することで、何を優先するかを決定できます。 。参照:

    • 関数パラメータとUSING句を使用したJOINの結果の間の名前の競合

    もっとあります:

    • RETURNINGには複雑さがあります UPSERTの条項。参照:

      • PostgreSQLでONCONFLICTを使用してRETURNINGを使用するにはどうすればよいですか?
    • 文字列リテラル(テキスト定数)は一重引用符で囲む必要があります:'OK'、 "OK"ではありません 。参照:

      • PostgreSQLで一重引用符でテキストを挿入
    • 変数の割り当ては、他のプログラミング言語よりも比較的コストがかかります。 plpgsqlで最高のパフォーマンスを得るには、割り当てを最小限に抑えてください。 SQLステートメントで可能な限り直接実行してください。

    • VOLATILE COST 100 関数のデフォルトのデコレータです。それらを詳しく説明する必要はありません。

    Postgres9.4以前ではUPSERTなし

    ...
       IF EXISTS (SELECT FROM pracownicy p
                 WHERE  p.id_pracownika = hire.id_pracownika) THEN
          RETURN 'JUZ ISTNIEJE';
       ELSE
          INSERT INTO pracownicy(id_pracownika,imie,nazwisko,miasto,pensja)
          VALUES (hire.id_pracownika,hire.imie,hire.nazwisko,hire.miasto,hire.pensja);
        
          RETURN 'OK';
       END IF;
    ...
    

    EXISTS内 式、SELECT リストは関係ありません。 SELECT id_pracownikaSELECT 1 、またはSELECT 1/0 -すべて同じです。空のSELECTを使用するだけです リスト。重要なのは、適格な行の存在だけです。参照:

    • EXISTSサブクエリで読みやすいものは何ですか?


    1. SQLServerデータベースですべての外部キー制約を無効にする方法-SQLServer/TSQLチュートリアルパート77

    2. テーブル式の基礎、パート5 – CTE、論理的考慮事項

    3. PostgreSQLでのAtanh()のしくみ

    4. MacでSQLServer2017と2019を同時に実行する方法