sql >> Databasteknik >  >> RDS >> PostgreSQL

VÄLJ eller UTFÖR i en PL/pgSQL-funktion

I plpgsql-kod, SELECT utan ett mål utlöser ett fel. Men det gör du uppenbarligen inte vill ha SELECT INTO , du vill bara ställa in statusen för FOUND . Du skulle använda PERFORM för det.

  • SELECT höjer undantag i PL/pgSQL-funktionen

Ännu bättre , använd IF EXISTS ... . Överväg denna omskrivning av din funktion:

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$;

Om EXISTS :

  • PL/pgSQL kontrollerar om en rad finns

Den andra viktiga punkten :

  • Använd RETURNING satsen i INSERT sats istället för en ytterligare SELECT .

Postgres 9.5+

I Postgres 9.5 eller senare använder du INSERT ... ON CONFLICT DO NOTHING (a.k.a. "UPSERT") istället.
Du skulle ha UNIQUE begränsningar på "Articulo"("Nombre", "idTipo", "idFamilia") och "ArticuloMarca"("idArticulo", "idMarca") och sedan:

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$;

Detta är snabbare, enklare och mer pålitligt. De tillagda slingorna utesluter eventuella återstående tävlingsförhållanden med samtidiga skrivningar (samtidigt som knappast tillför någon kostnad). Utan samtidiga skrivningar kan du förenkla. Detaljerad förklaring:

  • Är SELECT eller INSERT i en funktion utsatt för tävlingsförhållanden?
  • Hur använder man RETURNING med ON CONFLICT i PostgreSQL?

Bortsett från:använd lagliga identifierare med små bokstäver för att undvika alla bullriga citattecken.



  1. Få tabellkolumnnamn i MySQL?

  2. Är det möjligt att göra en rekursiv SQL-fråga?

  3. Entity-Attribute-Value Tabelldesign

  4. Java Crosstab - förberedd uttalandefråga