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

PL/pgSQL関数のSELECTまたはPERFORM

    plpgsqlコードでは、SELECT ターゲットがないとエラーが発生します。しかし、あなたは明らかにしません SELECT INTOが欲しい 、FOUNDのステータスを設定したいだけです 。 PERFORMを使用します そのために。

    • SELECTはPL/pgSQL関数で例外を発生させます

    より良い、それでもIF EXISTS ...を使用します 。関数の次の書き直しを検討してください:

    CREATE OR REPLACE FUNCTION "insertarNuevoArticulo"( nombrearticulo text, descripcion text, idtipo int, idfamilia bigint, artstock int, minstock int, maxstock int, idmarca bigint, precio real, marcastock int)
      RETURNS boolean
      LANGUAGE plpgsql AS
    $func$
    DECLARE
        _id_articulo "Articulo"."idArticulo"%TYPE;
    BEGIN
        SELECT a."idArticulo" INTO _id_articulo
        FROM   "Articulo" a
        WHERE  a."Nombre" = $1 AND a."idTipo" = $3 AND a."idFamilia" = $4;
    
        IF NOT FOUND THEN
            INSERT INTO "Articulo"("Nombre", "Descripcion", "idTipo", "idFamilia", "Stock", "MinStock", "MaxStock")
            VALUES ($1, $2, $3, $4, $5, $6, $7)
            RETURNING "Articulo"."idArticulo" INTO _id_articulo;
        END IF;
    
       IF EXISTS (SELECT FROM "ArticuloMarca" a
                  WHERE a."idArticulo" = _id_articulo AND a."idMarca" = $8) THEN
          RETURN false;
       ELSE
          INSERT INTO "ArticuloMarca"("idArticulo", "idMarca", "PrecioReferencial", "Stock")
          VALUES (_id_articulo, $8, $9, $10);
          RETURN true;
        END IF;
    END
    $func$;
    

    EXISTSについて :

    • 行が存在するかどうかをチェックするPL/pgSQL

    その他の重要なポイント

    • RETURNINGを使用します INSERTの句 追加のSELECTの代わりにステートメント 。

    Postgres 9.5+

    Postgres 9.5以降では、INSERT ... ON CONFLICT DO NOTHINGを使用します。 (別名「UPSERT」)代わりに。
    UNIQUEがあります。 "Articulo"("Nombre", "idTipo", "idFamilia")の制約 および"ArticuloMarca"("idArticulo", "idMarca") そして:

    CREATE OR REPLACE FUNCTION insert_new_articulo( nombrearticulo text, descripcion text, idtipo int, idfamilia bigint, artstock int, minstock int, maxstock int, idmarca bigint, precio real, marcastock int)
      RETURNS boolean
      LANGUAGE plpgsql AS
    $func$
    DECLARE
        _id_articulo "Articulo"."idArticulo"%TYPE;
    BEGIN
       LOOP
          SELECT "idArticulo" INTO _id_articulo
          FROM   "Articulo"
          WHERE  "Nombre" = $1 AND "idTipo" = $3 AND "idFamilia" = $4;
    
          EXIT WHEN FOUND;
    
          INSERT INTO "Articulo"("Nombre", "Descripcion", "idTipo", "idFamilia", "Stock", "MinStock", "MaxStock")
          VALUES ($1, $2, $3, $4, $5, $6, $7)
          ON     CONFLICT (tag) DO NOTHING
          RETURNING "idArticulo" INTO _id_articulo;
    
          EXIT WHEN FOUND;
       END LOOP;
    
       LOOP
          INSERT INTO "ArticuloMarca"("idArticulo", "idMarca", "PrecioReferencial", "Stock")
          VALUES (_id_articulo, $8, $9, $10)
          ON     CONFLICT ("idArticulo", "idMarca") DO NOTHING;
    
          IF FOUND THEN
             RETURN true;
          END IF;
    
          IF EXISTS (SELECT FROM "ArticuloMarca"
                     WHERE "idArticulo" = _id_articulo AND "idMarca" = $8) THEN
             RETURN false;
          END IF;
       END LOOP;
    END
    $func$;
    

    これは、より速く、より簡単で、より信頼性があります。追加されたループは、同時書き込みによる残りの競合状態を除外します(コストはほとんど追加されません)。同時書き込みがなくても、単純化できます。詳細な説明:

    • 関数内のSELECTまたはINSERTは競合状態になりやすいですか?
    • PostgreSQLでONCONFLICTを使用してRETURNINGを使用するにはどうすればよいですか?

    余談ですが、うるさい二重引用符をすべて避けるために、合法的な小文字の識別子を使用してください。



    1. PostgreSQL、レシピで材料を計算するための複雑なクエリ

    2. Access2016のデータセットビューでテーブルを作成する方法

    3. Access2016でデータベースをテンプレートとして保存する方法

    4. 文字列->java.util.Date->java.sql.Date(タイムスタンプ付き)