尝试学习pgSQL中的异常处理(PostgreSQL 9.1)。以下SP失败并带有
ERROR: insert or update on table "dx" violates foreign key constraint "fk_icd9"
SQL state: 23503
Detail: Key (cicd9, cdesc)=(244.9, testing1) is not present in table "icd9".
fk_icd9从表dx定义为:
CONSTRAINT fk_icd9 FOREIGN KEY (cicd9, cdesc)
REFERENCES icd9 (cicd9, cdesc) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED
我对SP的尝试是:
CREATE OR REPLACE FUNCTION g_test() RETURNS void AS $$
DECLARE
r View_dx%rowtype;
BEGIN
r.cicd9 := '244.9';
r.groupid := 'BBBB CCCC 199971230';
r.tposted := '2013-08-30 17:45:45'::timestamp;
r.cdesc := 'testing1';
LOOP
BEGIN
UPDATE dx SET cdesc = r.cdesc
WHERE cicd9 = r.cicd9 AND groupid = r.groupid AND tposted = r.tposted;
EXCEPTION
WHEN others THEN
INSERT INTO icd9(cicd9, cdesc) VALUES (r.cicd9, r.cdesc);
END;
IF FOUND THEN
RETURN;
END IF;
END LOOP;
END; $$ LANGUAGE plpgsql;
我正在尝试更新第二个表icd9中具有外键约束的表dx。如果由于此约束而导致dx表更新失败,那么我想在父icd9表中插入新记录,然后循环回第一个表dx进行更新。
我做错了什么?这是怎么做到的?
编辑#1:编辑如下所示的代码:
create or replace function g_savedx3() returns void as
$$
DECLARE
_cicd9 character varying(8);
_groupid character varying(33);
_tposted timestamp without time zone;
_cdesc character varying(80);
BEGIN
_cicd9 := '244.9';
_groupid := 'BBBBB AAAAA 199998';
_tposted := '2013-08-30 17:45:45'::timestamp;
_cdesc := 'testing109';
LOOP
BEGIN
RAISE NOTICE 'About to update ';
UPDATE dx SET cdesc = _cdesc
WHERE
cicd9 = _cicd9 and
groupid = _groupid and tposted = _tposted;
RAISE NOTICE 'Updated in g_saveDx3';
IF FOUND THEN
RETURN;
END IF;
EXCEPTION
WHEN others THEN
RAISE NOTICE 'In exception g_saveDx3, about to insert';
INSERT INTO icd9(cicd9,cdesc) VALUES (_cicd9, _cdesc);
RAISE NOTICE 'In exception inserted';
END;
END LOOP;
END;
$$
LANGUAGE plpgsql;
select g_savedx3();
收到以下消息:
注意:即将更新 注意:已在g_saveDx3
中更新错误:在表“dx”上插入或更新违反外键约束“fk_icd9” 详细信息:表“icd9”中不存在键(cicd9,cdesc)=(244.9,testing109)。 **********错误**********
错误:在表“dx”上插入或更新违反外键约束“fk_icd9” SQL状态:23503 细节:表“icd9”中没有键(cicd9,cdesc)=(244.9,testing109)。
注意:我在Tom {(2004)
的updates violating foreign constraints找到了一个旧条目是的......你期待RI触发器在此期间触发 plpgsql函数,但实际上它们在外部完成时会触发 调用plpgsql函数的语句。
关于这是否真的最重要,一直存在争议 理想的行为,但现在就是这样。
如果仍然如此,它可能会解释问题。任何想法如何修复我的代码? (应该有用吗?)谢谢。
***如下所述,我猜这是默认行为,在我的情况下,导致在完成plpgsql函数后调用异常。可以使用以下命令更改此行为(PostgreSQL 9.1)。
SET CONSTRAINTS ALL IMMEDIATE;
需要做出这项工作
如果它有任何方位,这里是ICD9表的定义:
CREATE TABLE icd9
(
recid serial NOT NULL,
cicd9 character varying(8),
cdesc character varying(80) NOT NULL,
"timestamp" timestamp without time zone DEFAULT now(),
modified timestamp without time zone DEFAULT now(),
chronic boolean NOT NULL DEFAULT false,
CONSTRAINT pk_icd9_recid PRIMARY KEY (recid),
CONSTRAINT constraint_cdesc UNIQUE (cicd9, cdesc),
CONSTRAINT desccheck CHECK (cdesc::text <> ''::text)
)
WITH (
OIDS=FALSE
);
答案 0 :(得分:2)
在你的循环中你有
IF FOUND THEN
RETURN;
END IF;
这会在循环进入INSERT
后的下一次迭代之前结束该函数,因为该命令也设置了FOUND
。
你想要的是:
LOOP
BEGIN
UPDATE dx SET cdesc = r.cdesc
WHERE cicd9 = r.cicd9 AND groupid = r.groupid AND tposted = r.tposted;
IF FOUND THEN
RETURN;
END IF;
EXCEPTION
WHEN others THEN
INSERT INTO icd9(cicd9, cdesc) VALUES (r.cicd9, r.cdesc);
END;
END LOOP;
答案 1 :(得分:1)
切换到老式的调试。这是我的代码,它确实插入。
create or replace function f () returns void as
$$
DECLARE
newval integer :=3 ;
BEGIN
LOOP
BEGIN
RAISE NOTICE 'About to update ';
UPDATE B SET ID2 = newval;
RAISE NOTICE 'Updated ';
IF FOUND THEN
RETURN;
END IF;
EXCEPTION
WHEN others THEN
RAISE NOTICE 'In exception , about to insert';
INSERT INTO a VALUES (newval);
RAISE NOTICE 'In exception inserted';
END;
END LOOP;
END;
$$
LANGUAGE plpgsql;
执行:
select f();
NOTICE: About to update
NOTICE: In exception , about to insert
NOTICE: In exception inserted
NOTICE: About to update
NOTICE: Updated
表定义:
test=# \d+ a
Table "w2gi.a"
Column | Type | Modifiers | Storage | Stats target | Description
--------+---------+-----------+---------+--------------+-------------
id | integer | not null | plain | |
Indexes:
"a_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "b" CONSTRAINT "b_id2_fkey" FOREIGN KEY (id2) REFERENCES a(id)
Has OIDs: no
test=# \d+ b
Table "w2gi.b"
Column | Type | Modifiers | Storage | Stats target | Description
--------+---------+-----------+---------+--------------+-------------
id1 | integer | | plain | |
id2 | integer | | plain | |
Foreign-key constraints:
"b_id2_fkey" FOREIGN KEY (id2) REFERENCES a(id)
Has OIDs: no