触发器可能违反postgresql中的外键

触发器可能违反postgresql中的外键,postgresql,foreign-keys,Postgresql,Foreign Keys,我在postgres中创建了一些表,在一个表和另一个表之间添加了一个外键,并设置为DELETE以级联。奇怪的是,我有一些字段似乎违反了这个约束 这是正常的行为吗?如果是这样的话,有没有办法达到我想要的行为(不可能有违规行为) 编辑: 我最初创建外键作为createtable的一部分,只是使用 ... REFERENCES product (id) ON UPDATE CASCADE ON DELETE CASCADE pgAdmin3给出的当前代码是 ALTER TABLE cultivar

我在postgres中创建了一些表,在一个表和另一个表之间添加了一个外键,并设置为DELETE以级联。奇怪的是,我有一些字段似乎违反了这个约束

这是正常的行为吗?如果是这样的话,有没有办法达到我想要的行为(不可能有违规行为)

编辑:

我最初创建外键作为createtable的一部分,只是使用

... 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创建表、填充表等等。问题是,我不知道它是如何进入这种情况的。我只知道我创建了两个表,添加了外键,插入了大量数据,并让系统运行了一段时间。然后,在修复错误时,我遇到了外键约束不成立的这些字段。现在我认为这是不可能的,但也许它们只是以一次性的方式实现的?检查了插入/更新,但再也没有检查过?我重新创建了错误,并在下面的答案中发布了一个测试用例。从来没有真正违反过约束。我意识到我处理这种情况有点奇怪,所以我付出了额外的努力,复制了导致我最初问题的情况。