2008-09-22 27 views
6

Nếu tôi có một bảng trong MySQL đại diện cho một lớp cơ sở, và tôi có một loạt các bảng biểu diễn các trường trong các lớp dẫn xuất, mỗi bảng tham chiếu trở lại bảng cơ sở với khóa ngoài, có cách nào để có được MySQL để thực thi mối quan hệ một-một giữa bảng dẫn xuất và bảng cơ sở, hay điều này phải được thực hiện trong mã?Các khóa ngoài của MySQL - cách thực thi một đối một trên các bảng?

Sử dụng lược đồ bẩn 'n' nhanh sau đây làm ví dụ, có cách nào để nhận MySQL để đảm bảo rằng các hàng trong cả product_cd và product_dvd không thể chia sẻ cùng một product_id không? Có cách nào tốt hơn để thiết kế lược đồ để cho phép cơ sở dữ liệu thực thi mối quan hệ này hay không đơn giản là không thể?

CREATE TABLE IF NOT EXISTS `product` (
    `product_id` int(10) unsigned NOT NULL auto_increment, 
    `product_name` varchar(50) NOT NULL, 
    `description` text NOT NULL, 
    PRIMARY KEY (`product_id`) 
) ENGINE = InnoDB; 

CREATE TABLE `product_cd` (
    `product_cd_id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 
    `product_id` INT UNSIGNED NOT NULL , 
    `artist_name` VARCHAR(50) NOT NULL , 
    PRIMARY KEY (`product_cd_id`) , 
    INDEX (`product_id`) 
) ENGINE = InnoDB; 

ALTER TABLE `product_cd` ADD FOREIGN KEY (`product_id`) 
    REFERENCES `product` (`product_id`) 
    ON DELETE RESTRICT ON UPDATE RESTRICT ; 

CREATE TABLE `product_dvd` (
    `product_dvd_id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 
    `product_id` INT UNSIGNED NOT NULL , 
    `director` VARCHAR(50) NOT NULL , 
    PRIMARY KEY (`product_dvd_id`) , 
    INDEX (`product_id`) 
) ENGINE = InnoDB; 

ALTER TABLE `product_dvd` ADD FOREIGN KEY (`product_id`) 
    REFERENCES `product` (`product_id`) 
    ON DELETE RESTRICT ON UPDATE RESTRICT ; 

@Skliwz, bạn có thể vui lòng cung cấp chi tiết hơn về cách trigger có thể được sử dụng để thực thi các hạn chế này với sơ đồ cung cấp?

@boes, điều đó thật tuyệt vời. Làm thế nào nó hoạt động trong các tình huống mà bạn có con của một đứa trẻ? Ví dụ: nếu chúng tôi đã thêm product_movie và tạo product_dvd là con của product_movie? Nó sẽ là một cơn ác mộng bảo trì để làm cho các ràng buộc kiểm tra cho product_dvd có yếu tố trong tất cả các loại trẻ em là tốt?

+5

Sử dụng nhận xét thay vì chỉnh sửa câu hỏi của bạn. – epochwolf

Trả lời

3

Để đảm bảo rằng sản phẩm là hoặc cd hoặc dvd, tôi sẽ thêm cột loại và biến nó thành một phần của khóa chính. Trong cột dẫn xuất, bạn thêm ràng buộc kiểm tra cho kiểu. Trong ví dụ này tôi đặt cd thành 1 và bạn có thể tạo dvd = 2 và cứ như vậy cho mỗi bảng dẫn xuất.

CREATE TABLE IF NOT EXISTS `product` (
`product_id` int(10) unsigned NOT NULL auto_increment, 
'product_type' int not null, 
`product_name` varchar(50) NOT NULL, 
`description` text NOT NULL, 
PRIMARY KEY (`product_id`, 'product_type') 
) ENGINE = InnoDB; 

CREATE TABLE `product_cd` (
`product_id` INT UNSIGNED NOT NULL , 
'product_type' int not null default(1) check ('product_type' = 1) 
`artist_name` VARCHAR(50) NOT NULL , 
PRIMARY KEY (`product_id`, 'product_type') , 
) ENGINE = InnoDB; 

ALTER TABLE `product_cd` ADD FOREIGN KEY (`product_id`, 'product_type') 
REFERENCES `product` (`product_id`, 'product_type') 
ON DELETE RESTRICT ON UPDATE RESTRICT ; 
+2

-1. MySQL bỏ qua các ràng buộc kiểm tra. –

1

Nếu bạn sử dụng MySQL 5.x, bạn có thể sử dụng trình kích hoạt cho các loại ràng buộc này.

Tùy chọn khác (dưới tối ưu) sẽ là sử dụng cột "loại" trong bảng chính để bỏ qua trùng lặp trùng lặp và có thể chọn "bảng tiện ích mở rộng" chính xác.

+1

Làm cách nào bạn có thể sử dụng trình kích hoạt cho loại ràng buộc này? Bạn có thể vui lòng cung cấp một ví dụ? – Shabbyrobe

3

Bạn chỉ có thể thêm khóa ngoại từ một khóa chính vào khóa chính khác. Vì PK phải là duy nhất, bạn tự động có được mối quan hệ một-một.

+0

Sử dụng InnoDB, với tôi điều này không hiệu quả. ngay cả sau khi kỹ thuật đảo ngược kịch bản, mối quan hệ vẫn là một-nhiều. Cách duy nhất hiệu quả để duy trì mối quan hệ một-một là thiết lập cột khóa ngoài thành UNIQUE; theo cách này, chúng tôi chắc chắn chỉ có một bản ghi sẽ được tạo cho nó. Và nếu bạn cố gắng vi phạm ràng buộc này, bạn nhận được lỗi sau (MySQL 5.1): '1 lỗi (s) lưu thay đổi vào bảng' testdb'.'table4': INSERT INTO 'testdb'.'table4' ('idtable4',' label', 'table3_idtable3') VALUES (0, 'soso', 0) 1062: Mục nhập trùng lặp '0' cho khóa 'table3_idtable3_UNIQUE' Hoàn thành cuộn lùi' – Hanynowsky

4

Nếu bạn đã thoát khỏi sản phẩm-dvd-idsản phẩm-cd-id, và sử dụng các sản phẩm-id làm khóa chính cho tất cả ba bảng, ít nhất bạn có thể chắc chắn rằng không có hai DVD hoặc không có hai đĩa CD nào sử dụng cùng một tên sản phẩm -id. Thêm vào đó sẽ có ít id để theo dõi.

Và bạn có thể cần một loại cột loại trong bảng sản phẩm.

8

Có thể đạt được mối quan hệ 1: 0-1 hoặc 1: 1 bằng cách xác định ràng buộc duy nhất trên cột của khóa ngoại, do đó chỉ có một kết hợp có thể tồn tại. Thông thường, đây sẽ là khóa chính của bảng con.

Nếu FK nằm trên khóa chính hoặc khóa duy nhất của các bảng được tham chiếu, nó sẽ hạn chế chúng thành các giá trị có trong dấu ngoặc đơn và ràng buộc duy nhất trên cột hoặc cột giới hạn chúng thành tính duy nhất. Điều này có nghĩa là bảng con chỉ có thể có các giá trị tương ứng với cha mẹ trong các cột bị ràng buộc và mỗi hàng phải có một giá trị duy nhất. Thực hiện điều này thực thi rằng bảng con sẽ có tối đa một hàng tương ứng với bản ghi cha.

+4

Trừ 1 vì nó không trả lời câu hỏi, không cung cấp một ví dụ và vẫn nhận được rất nhiều phiếu bầu. Một phần của câu hỏi là: 'có cách nào để đảm bảo rằng các hàng trong cả product_cd và product_dvd không thể chia sẻ cùng một product_id'. Bạn không trả lời câu hỏi đó. Ai sẽ cho bạn những phiếu bầu này? – boes

1

Cách hiệu quả duy nhất để duy trì một one-to-one mối quan hệ là để thiết lập các cột nước ngoài chìa khóa để UNIQUE; theo cách này, chúng tôi chắc chắn chỉ có một bản ghi sẽ được tạo cho nó. Và nếu bạn cố gắng vi phạm ràng buộc này, bạn sẽ gặp phải lỗi sau (MySQL 5.1):

`1 error(s) saving changes to table testdb`.table4: INSERT INTO testdb.table4 (idtable4, label, table3_idtable3) VALUES (0, 'soso', 0) 1062: Duplicate entry '0' for key 'table3_idtable3_UNIQUE' Rollback complete 
Các vấn đề liên quan