2010-10-18 32 views
20

Tôi đã tạo một số bảng trong postgres, thêm khóa ngoài từ bảng này sang bảng khác và đặt ON DELETE thành CASCADE. Thật kỳ lạ, tôi có một số trường dường như vi phạm ràng buộc này.Các khóa ngoại trong postgresql có thể bị vi phạm bởi kích hoạt

Đây có phải là hành vi bình thường không? Và nếu có, có cách nào để có được hành vi mà tôi muốn (không có vi phạm)?

Edit:

tôi orginaly tạo phím nước ngoài như là một phần của CREATE TABLE, chỉ cần sử dụng

... REFERENCES product (id) ON UPDATE CASCADE ON DELETE CASCADE 

Mã pgAdmin3 hiện cho được

ALTER TABLE cultivar 
    ADD CONSTRAINT cultivar_id_fkey FOREIGN KEY (id) 
     REFERENCES product (id) MATCH SIMPLE 
     ON UPDATE CASCADE ON DELETE CASCADE; 

Chỉnh sửa 2:

Để làm rõ, tôi có một nghi ngờ lén lút rằng các ràng buộc chỉ được kiểm tra khi cập nhật s/chèn xảy ra nhưng sau đó không bao giờ nhìn lại. Thật không may tôi không biết đủ về postgres để tìm hiểu xem điều này là đúng hay làm thế nào các lĩnh vực có thể kết thúc trong cơ sở dữ liệu mà không kiểm tra được chạy.

Nếu trường hợp này xảy ra, có cách nào để kiểm tra tất cả các khóa ngoại và khắc phục các sự cố đó không?

Sửa 3:

Vi phạm chế có thể được gây ra bởi một nút bấm bị lỗi, xem dưới đây

+0

chỉ để kiểm tra sự lành mạnh, bạn có thể đăng tuyên bố bạn đã sử dụng để tạo FK không? –

+0

Bạn đang sử dụng phiên bản PG nào? – Kuberchaun

+0

Tôi đang sử dụng phiên bản 8.3 –

Trả lời

5

Tất cả những gì tôi đã đọc dường như cho đến nay để thấy rằng trở ngại chỉ kiểm tra khi dữ liệu được chèn vào. (Hoặc khi ràng buộc được tạo ra) Ví dụ: the manual on set constraints.

Điều này có ý nghĩa và - nếu cơ sở dữ liệu hoạt động đúng - phải đủ tốt. Tôi vẫn tò mò làm thế nào tôi quản lý để phá vỡ này hoặc nếu tôi chỉ đọc tình hình sai và không bao giờ có một sự vi phạm ràng buộc thực sự để bắt đầu với.

Dù bằng cách nào, trường hợp đóng cửa: -/

------- CẬP NHẬT --------

Có chắc chắn là một sự vi phạm hạn chế, gây ra bởi một nút bấm bị lỗi. Đây là một kịch bản để nhân rộng:

-- 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; 
+1

Không bao giờ có một sự vi phạm ràng buộc thực sự. – Unreason

+0

Tôi nhận ra rằng tôi đã xử lý tình huống này một cách kỳ lạ, vì vậy tôi đã nỗ lực thêm và nhân rộng tình hình đã gây ra các vấn đề ban đầu của tôi. –

24

Tôi đã cố gắng tạo một ví dụ đơn giản cho thấy ràng buộc khóa ngoài được thực thi. Với ví dụ này, tôi chứng minh tôi không được phép nhập dữ liệu vi phạm fk và tôi chứng minh rằng nếu fk không được đặt trong khi chèn, và tôi bật fk, ràng buộc fk ném một lỗi cho tôi biết dữ liệu vi phạm fk. Vì vậy, tôi không nhìn thấy cách bạn có dữ liệu trong bảng vi phạm một fk được đặt ra. Tôi đang trên 9,0, nhưng điều này không nên khác nhau trên 8,3. Nếu bạn có thể hiển thị ví dụ hoạt động để chứng minh sự cố có thể hữu ích.

--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; 
Các vấn đề liên quan