sql >> Database teknologi >  >> RDS >> PostgreSQL

VÆLG eller UDFØR i en PL/pgSQL-funktion

I plpgsql-kode, SELECT uden et mål udløser en fejl. Men det gør du åbenbart ikke ønsker SELECT INTO , du vil bare indstille status for FOUND . Du ville bruge PERFORM for det.

  • SELECT rejser undtagelser i PL/pgSQL-funktionen

Bedre, dog , brug IF EXISTS ... . Overvej denne omskrivning af 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 kontrollerer, om der findes en række

Den anden vigtige pointe :

  • Brug RETURNING klausul af INSERT sætning i stedet for en ekstra SELECT .

Postgres 9.5+

I Postgres 9.5 eller nyere, brug INSERT ... ON CONFLICT DO NOTHING (a.k.a. "UPSERT") i stedet.
Du ville have UNIQUE begrænsninger på "Articulo"("Nombre", "idTipo", "idFamilia") og "ArticuloMarca"("idArticulo", "idMarca") og derefter:

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

Dette er hurtigere, enklere og mere pålideligt. De tilføjede loops udelukker eventuelle resterende løbsbetingelser med samtidige skrivninger (mens det næsten ikke tilføjer nogen omkostninger). Uden samtidige skrivninger kan du forenkle. Detaljeret forklaring:

  • Er SELECT eller INSERT i en funktion, der er tilbøjelig til løbsforhold?
  • Hvordan bruger man RETURNING med ON CONFLICT i PostgreSQL?

Til side:Brug lovlige identifikatorer med små bogstaver for at undgå alle de larmende dobbelte anførselstegn.



  1. Lær det grundlæggende i Java-logging

  2. Hvilke rækker returneres ved brug af LIMIT med OFFSET i MySQL?

  3. mærkelig tegnkodning af lagrede data, gammelt script viser dem fint, nyt gør det ikke

  4. Hvad betyder nøgleordet KEY?