sql >> Database >  >> RDS >> PostgreSQL

SELECT of PERFORM in een PL/pgSQL-functie

In plpgsql-code, SELECT zonder een doel veroorzaakt een fout. Maar dat doe je duidelijk niet wil SELECT INTO , je wilt alleen de status van FOUND . instellen . Je zou PERFORM . gebruiken daarvoor.

  • SELECT roept uitzondering op in PL/pgSQL-functie

Beter, maar toch , gebruik IF EXISTS ... . Overweeg deze herschrijving van uw functie:

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

Over EXISTS :

  • PL/pgSQL controleren of een rij bestaat

Het andere belangrijke punt :

  • Gebruik de RETURNING clausule van de INSERT statement in plaats van een extra SELECT .

Postgres 9.5+

Gebruik in Postgres 9.5 of hoger INSERT ... ON CONFLICT DO NOTHING (ook bekend als "UPSERT").
Je zou UNIQUE hebben beperkingen op "Articulo"("Nombre", "idTipo", "idFamilia") en "ArticuloMarca"("idArticulo", "idMarca") en dan:

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

Dit is sneller, eenvoudiger en betrouwbaarder. De toegevoegde lussen sluiten eventuele resterende racecondities met gelijktijdige schrijfbewerkingen uit (terwijl er nauwelijks kosten aan verbonden zijn). Zonder gelijktijdige schrijfbewerkingen kunt u vereenvoudigen. Gedetailleerde uitleg:

  • Is SELECT of INSERT in een functie die vatbaar is voor race-omstandigheden?
  • Hoe RETURNING gebruiken met ON CONFLICT in PostgreSQL?

Terzijde:gebruik legale identificatiecodes in kleine letters om alle luidruchtige dubbele aanhalingstekens te vermijden.



  1. Efficiënte manier om alle rijen in een tabel bij te werken

  2. Hoe een Rest API te bouwen met Spring Boot met behulp van MySQL en JPA

  3. postgresql - vervang alle instanties van een string in het tekstveld

  4. PostgreSQL:prestatie pg_dump, pg_restore verbeteren