触发器可能违反postgresql中的外键
我在postgres中创建了一些表,在一个表和另一个表之间添加了一个外键,并设置为DELETE以级联。奇怪的是,我有一些字段似乎违反了这个约束 这是正常的行为吗?如果是这样的话,有没有办法达到我想要的行为(不可能有违规行为) 编辑: 我最初创建外键作为createtable的一部分,只是使用触发器可能违反postgresql中的外键,postgresql,foreign-keys,Postgresql,Foreign Keys,我在postgres中创建了一些表,在一个表和另一个表之间添加了一个外键,并设置为DELETE以级联。奇怪的是,我有一些字段似乎违反了这个约束 这是正常的行为吗?如果是这样的话,有没有办法达到我想要的行为(不可能有违规行为) 编辑: 我最初创建外键作为createtable的一部分,只是使用 ... REFERENCES product (id) ON UPDATE CASCADE ON DELETE CASCADE pgAdmin3给出的当前代码是 ALTER TABLE cultivar
... REFERENCES product (id) ON UPDATE CASCADE ON DELETE CASCADE
pgAdmin3给出的当前代码是
ALTER TABLE cultivar
ADD CONSTRAINT cultivar_id_fkey FOREIGN KEY (id)
REFERENCES product (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE;
编辑2:
为了澄清这一点,我暗自怀疑,只有在更新/插入发生时才会检查约束,但之后就再也不会检查约束了。不幸的是,我对postgres了解不够,无法确定这是否属实,也无法确定字段如何在不运行这些检查的情况下在数据库中结束
如果是这种情况,是否有办法检查所有外键并修复这些问题
编辑3:
约束冲突可能是由错误的触发器引起的,请参见下文到目前为止,我阅读的所有内容似乎都表明,只有在插入数据时才检查约束。(或在创建约束时)例如 这是有意义的,如果数据库工作正常,应该足够好了。我仍然很好奇,我是如何设法绕过这一点的,或者如果我只是错误地理解了这种情况,并且从一开始就没有真正违反约束 无论哪种方式,案例结束:-/ -------更新-------- 确实有一个约束冲突,是由错误的触发器引起的。下面是要复制的脚本:
-- Create master table
CREATE TABLE product
(
id INT NOT NULL PRIMARY KEY
);
-- Create second table, referencing the first
CREATE TABLE example
(
id int PRIMARY KEY REFERENCES product (id) ON DELETE CASCADE
);
-- Create a (broken) trigger function
--CREATE LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION delete_product()
RETURNS trigger AS
$BODY$
BEGIN
DELETE FROM product WHERE product.id = OLD.id;
-- This is an error!
RETURN null;
END;
$BODY$
LANGUAGE plpgsql;
-- Add it to the second table
CREATE TRIGGER example_delete
BEFORE DELETE
ON example
FOR EACH ROW
EXECUTE PROCEDURE delete_product();
-- Now lets add a row
INSERT INTO product (id) VALUES (1);
INSERT INTO example (id) VALUES (1);
-- And now lets delete the row
DELETE FROM example WHERE id = 1;
/*
Now if everything is working, this should return two columns:
(pid,eid)=(1,1). However, it returns only the example id, so
(pid,eid)=(0,1). This means the foreign key constraint on the
example table is violated.
*/
SELECT product.id AS pid, example.id AS eid FROM product FULL JOIN example ON product.id = example.id;
我试图创建一个简单的示例,演示如何强制执行外键约束。在本例中,我证明了不允许输入违反fk的数据,并且证明了如果插入期间fk不在适当位置,并且我启用了fk,则fk约束会抛出一个错误,告诉我数据违反fk。所以我没有看到表中的数据是如何违反fk的。我在9.0上,但在8.3上应该没有什么不同。如果你能展示一个工作实例来证明你的问题,这可能会有所帮助
--CREATE TABLES--
CREATE TABLE parent
(
parent_id integer NOT NULL,
first_name character varying(50) NOT NULL,
CONSTRAINT pk_parent PRIMARY KEY (parent_id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE parent OWNER TO postgres;
CREATE TABLE child
(
child_id integer NOT NULL,
parent_id integer NOT NULL,
first_name character varying(50) NOT NULL,
CONSTRAINT pk_child PRIMARY KEY (child_id),
CONSTRAINT fk1_child FOREIGN KEY (parent_id)
REFERENCES parent (parent_id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)
WITH (
OIDS=FALSE
);
ALTER TABLE child OWNER TO postgres;
--CREATE TABLES--
--INSERT TEST DATA--
INSERT INTO parent(parent_id,first_name)
SELECT 1,'Daddy'
UNION
SELECT 2,'Mommy';
INSERT INTO child(child_id,parent_id,first_name)
SELECT 1,1,'Billy'
UNION
SELECT 2,1,'Jenny'
UNION
SELECT 3,1,'Kimmy'
UNION
SELECT 4,2,'Billy'
UNION
SELECT 5,2,'Jenny'
UNION
SELECT 6,2,'Kimmy';
--INSERT TEST DATA--
--SHOW THE DATA WE HAVE--
select parent.first_name,
child.first_name
from parent
inner join child
on child.parent_id = parent.parent_id
order by parent.first_name, child.first_name asc;
--SHOW THE DATA WE HAVE--
--DELETE PARENT WHO HAS CHILDREN--
BEGIN TRANSACTION;
delete from parent
where parent_id = 1;
--Check to see if any children that were linked to Daddy are still there?
--None there so the cascade delete worked.
select parent.first_name,
child.first_name
from parent
right outer join child
on child.parent_id = parent.parent_id
order by parent.first_name, child.first_name asc;
ROLLBACK TRANSACTION;
--TRY ALLOW NO REFERENTIAL DATA IN--
BEGIN TRANSACTION;
--Get rid of fk constraint so we can insert red headed step child
ALTER TABLE child DROP CONSTRAINT fk1_child;
INSERT INTO child(child_id,parent_id,first_name)
SELECT 7,99999,'Red Headed Step Child';
select parent.first_name,
child.first_name
from parent
right outer join child
on child.parent_id = parent.parent_id
order by parent.first_name, child.first_name asc;
--Will throw FK check violation because parent 99999 doesn't exist in parent table
ALTER TABLE child
ADD CONSTRAINT fk1_child FOREIGN KEY (parent_id)
REFERENCES parent (parent_id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE;
ROLLBACK TRANSACTION;
--TRY ALLOW NO REFERENTIAL DATA IN--
--DROP TABLE parent;
--DROP TABLE child;
为了检查是否正常,你可以发布你用来创建FK的语句吗?你使用的是什么版本的PG?给出一个小的运行示例如何重现你的问题。Ie sql创建表、填充表等等。问题是,我不知道它是如何进入这种情况的。我只知道我创建了两个表,添加了外键,插入了大量数据,并让系统运行了一段时间。然后,在修复错误时,我遇到了外键约束不成立的这些字段。现在我认为这是不可能的,但也许它们只是以一次性的方式实现的?检查了插入/更新,但再也没有检查过?我重新创建了错误,并在下面的答案中发布了一个测试用例。从来没有真正违反过约束。我意识到我处理这种情况有点奇怪,所以我付出了额外的努力,复制了导致我最初问题的情况。