PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

SELECT lub PERFORM w funkcji PL/pgSQL

W kodzie plpgsql, SELECT bez celu wyzwala błąd. Ale oczywiście nie chcesz SELECT INTO , chcesz tylko ustawić stan FOUND . Użyjesz PERFORM za to.

  • SELECT zgłasza wyjątek w funkcji PL/pgSQL

Jeszcze lepiej , użyj IF EXISTS ... . Rozważ przepisanie swojej funkcji:

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

O EXISTS :

  • PL/pgSQL sprawdzanie, czy wiersz istnieje

Inny ważny punkt :

  • Użyj RETURNING klauzula INSERT instrukcja zamiast dodatkowego SELECT .

Postgres 9.5+

W Postgresie 9.5 lub nowszym użyj INSERT ... ON CONFLICT DO NOTHING (inaczej „UPSERT”).
Mógłbyś UNIQUE ograniczenia dotyczące "Articulo"("Nombre", "idTipo", "idFamilia") i "ArticuloMarca"("idArticulo", "idMarca") a następnie:

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

Jest to szybsze, prostsze i bardziej niezawodne. Dodane pętle wykluczają wszelkie pozostałe warunki wyścigu z równoczesnymi zapisami (podczas gdy nie dodają prawie żadnych kosztów). Bez współbieżnych zapisów możesz uprościć. Szczegółowe wyjaśnienie:

  • Czy SELECT lub INSERT w funkcji podatnej na wyścigi?
  • Jak używać RETURNING z ON CONFLICT w PostgreSQL?

Na marginesie:używaj legalnych identyfikatorów pisanych małymi literami, aby uniknąć hałaśliwych podwójnych cudzysłowów.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PSQLException:bieżąca transakcja jest przerwana, polecenia ignorowane do końca bloku transakcji

  2. Wskazówki dotyczące przechowywania kopii zapasowych PostgreSQL na Amazon AWS

  3. PostgreSql :tablica Json do wierszy przy użyciu łączenia bocznego

  4. Kolumna dynamiczna w postgresie instrukcji SELECT

  5. Tablica elementów PostgreSQL, z których każdy jest kluczem obcym