plpgsqlコードでは、SELECT
ターゲットがないとエラーが発生します。しかし、あなたは明らかにしません SELECT INTO
が欲しい 、FOUND
のステータスを設定したいだけです 。 PERFORM
を使用します そのために。
- SELECTはPL/pgSQL関数で例外を発生させます
より良い、それでも 、IF EXISTS ...
を使用します 。関数の次の書き直しを検討してください:
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$;
EXISTS
について :
- 行が存在するかどうかをチェックするPL/pgSQL
その他の重要なポイント :
-
RETURNING
を使用しますINSERT
の句 追加のSELECT
の代わりにステートメント 。
Postgres 9.5+
Postgres 9.5以降では、INSERT ... ON CONFLICT DO NOTHING
を使用します。 (別名「UPSERT」)代わりに。
UNIQUE
があります。 "Articulo"("Nombre", "idTipo", "idFamilia")
の制約 および"ArticuloMarca"("idArticulo", "idMarca")
そして:
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$;
これは、より速く、より簡単で、より信頼性があります。追加されたループは、同時書き込みによる残りの競合状態を除外します(コストはほとんど追加されません)。同時書き込みがなくても、単純化できます。詳細な説明:
- 関数内のSELECTまたはINSERTは競合状態になりやすいですか?
- PostgreSQLでONCONFLICTを使用してRETURNINGを使用するにはどうすればよいですか?
余談ですが、うるさい二重引用符をすべて避けるために、合法的な小文字の識別子を使用してください。