私のデータベースにはこの関数があります:
CREATE OR REPLACE FUNCTION "insertarNuevoArticulo"(nombrearticulo character varying, descripcion text, idtipo integer, idfamilia bigint, artstock integer, minstock integer, maxstock integer, idmarca bigint, precio real, marcastock integer)
RETURNS boolean AS
$BODY$
DECLARE
articulo "Articulo"%ROWTYPE;
BEGIN
SELECT * INTO articulo FROM "Articulo" WHERE "Nombre" = $1 AND "idTipo"=$3 AND "idFamilia"=$4;
IF NOT FOUND THEN
INSERT INTO "Articulo" ("Nombre", "Descripcion", "idTipo", "idFamilia", "Stock", "MinStock", "MaxStock") Values ($1, $2, $3, $4, $5, $6, $7);
SELECT last_value
INTO articulo."idArticulo"
FROM "public"."Articulo_idArticulo_seq";
END IF;
SELECT * FROM "ArticuloMarca" AS am WHERE am."idArticulo" = articulo."idArticulo" and am."idMarca" = $8;
IF NOT FOUND THEN
Insert into "ArticuloMarca"("idArticulo", "idMarca", "PrecioReferencial", "Stock") Values (articulo."idArticulo", $8, $9, $10);
RETURN TRUE;
END IF;
RETURN FALSE;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION "insertarNuevoArticulo"(character varying, text, integer, bigint, integer, integer, integer, bigint, real, integer)
OWNER TO postgres;
しかし、使用しようとするとすぐに、結果を破棄する場合はPERFORM
を使用する必要があると表示されます。ここでの問題は、私がしたくないということです!私が宣言したarticulo
行にそれらが欲しいです!
私はこのステートメントを使用しています:
SELECT "insertarNuevoArticulo"('Acetaminofen', 'caro', '1' , '1', '8', '1', '10', '1', '150.7', '10');
そして、私が得るエラーは42601、構文エラーです! IDEを使用して作成している場合、どうなるでしょうか?問題について何か考えはありますか?
Plpgsqlコードでは、ターゲットのないSELECT
がエラーをトリガーします。しかし、あなたは明らかにnot_SELECT INTO
_を望んでおらず、FOUND
のステータスを設定したいだけです。そのためには PERFORM
を使用します。
より良い、まだ、_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 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$ LANGUAGE plpgsql;
_
EXISTS
について:
その他の主要なポイント:
RETURNING
の代わりに、INSERT
ステートメントの SELECT
句 を使用します。Postgres 9.5以降では、代わりにUPSERTを使用してください:(_INSERT ... ON CONFLICT DO NOTHING
_)。"Articulo"("Nombre", "idTipo", "idFamilia")
と"ArticuloMarca"("idArticulo", "idMarca")
にUNIQUE
制約があり、次のようになります。
_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 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$ LANGUAGE plpgsql;
_
これは、より速く、より簡単で、より信頼性があります。追加されたループは、同時書き込みによる残りの競合状態を除外します(コストはほとんど追加されません)。同時書き込みがなくても、単純化できます。詳細な説明:
余談ですが、すべての醜い 二重引用符 を避けるために、正当な小文字の識別子を使用してください。
この行は私には疑わしいように見え、おそらくあなたの悲しみを引き起こしているものです:
SELECT * FROM "ArticuloMarca" AS am WHERE am."idArticulo" = articulo."idArticulo" and am."idMarca" = $8;
関数内でSELECTを実行していますが、結果に対して何も実行していません。関数の前半で行ったように、SELECTINTOを実行する必要があります。