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 afINSERT
sætning i stedet for en ekstraSELECT
.
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.