2009-02-26 55 views
32

Tôi nghĩ rằng một khóa nước ngoài có nghĩa là một hàng duy nhất phải tham chiếu một hàng duy nhất, nhưng tôi đang xem xét một số bảng mà điều này chắc chắn không phải là trường hợp. Bảng 1 có cột1 với ràng buộc khóa ngoài trên cột2 trong bảng 2, NHƯNG có nhiều bản ghi trong bảng 2 có cùng giá trị trong cột2. Ngoài ra còn có chỉ mục không duy nhất trên cột2. Điều đó có nghĩa là gì? Ràng buộc khoá ngoại có đơn giản có nghĩa là ít nhất một bản ghi phải tồn tại với các giá trị đúng trong các cột bên phải không? Tôi nghĩ rằng nó có nghĩa là phải có chính xác một bản ghi như vậy (không chắc chắn như thế nào nulls phù hợp với hình ảnh, nhưng tôi ít quan tâm về điều đó vào lúc này).Một khóa ngoại có thể tham chiếu đến một chỉ mục không duy nhất không?

cập nhật: Rõ ràng, hành vi này là cụ thể đối với MySQL, đó là những gì tôi đã sử dụng, nhưng tôi đã không đề cập đến nó trong câu hỏi ban đầu của tôi.

+0

Bạn đang nói về cơ sở dữ liệu nào? –

+0

Loại cơ sở dữ liệu có quan trọng không? Tôi đã giả định nó là một quy tắc SQL chung. – bortzmeyer

Trả lời

38

Từ MySQL documentation:

InnoDB cho phép một nước ngoài ràng buộc khóa để tham chiếu một khóa không phải duy nhất. Đây là phần mở rộng của InnoDB cho SQL chuẩn.

Tuy nhiên, có lý do chính đáng để tránh các khóa ngoại trên các cột không được tham chiếu của bảng được tham chiếu. Đó là, ngữ nghĩa của "ON DELETE CASCADE" trong trường hợp đó là gì?

The documentation further advises:

Việc xử lý tài liệu tham khảo chính nước ngoài để phím nonunique hoặc phím có chứa giá trị NULL không được xác định rõ (...) Bạn nên sử dụng các phím nước ngoài mà tham khảo chỉ UNIQUE (bao gồm TIỂU) và NOT NULL.

+0

Cảm ơn bạn đã trích dẫn tài liệu của MySQL. Tôi đã không đề cập cụ thể đến MySQL trong câu hỏi của tôi, nhưng đó là những gì tôi đã sử dụng. Tôi sẽ cập nhật câu hỏi của tôi để phản ánh điều này. – allyourcode

+2

Tài liệu phiên bản 5.1 của MySQL đi xa hơn: "Việc xử lý các tham chiếu khóa ngoài tới các khóa không phải là [không] hoặc các khóa có giá trị NULL không được xác định rõ .... Bạn nên sử dụng khóa ngoài chỉ tham chiếu các phím UNIQUE và NOT NULL . " –

+0

Câu trả lời này sẽ tốt hơn với liên kết đến tài liệu được trích dẫn. – magnattic

7

Phân tích của bạn là chính xác; các khóa không nhất thiết phải là duy nhất và các ràng buộc sẽ hoạt động trên tập hợp các hàng phù hợp. Thường không phải là một hành vi hữu ích, nhưng tình huống có thể xuất hiện ở nơi bạn muốn.

+0

Cảm ơn sự giúp đỡ, Chaos. Điều này thực sự messes lên sự hiểu biết của tôi về các phím nước ngoài mặc dù ... – allyourcode

+0

Lúc đầu, tôi là một chút nhầm lẫn về những gì "phân tích của bạn" được cho là để đề cập đến. Đối với các độc giả khác, tôi nghĩ bạn có nghĩa là có thể có một khóa ngoại để tham chiếu đến nhiều hàng, miễn là có ít nhất một hàng. – allyourcode

+1

Sự hiểu biết của bạn về các khóa ngoại là đúng sai lầm, bởi vì đây là một câu trả lời không có thật. Ngay cả khi bạn tìm thấy một cơ sở dữ liệu mà bạn có thể làm điều này (tôi đã không thử nghiệm MySQL), nó sẽ rất, thiết kế cơ sở dữ liệu xấu _very_ để thực hiện một mối quan hệ khóa ngoại. – cdonner

3

Có, bạn có thể tạo khóa ngoài về cơ bản bất kỳ cột nào trong bất kỳ bảng nào. Hầu hết thời gian bạn sẽ tạo chúng vào khóa chính, mặc dù.

Nếu bạn sử dụng khóa ngoài không trỏ đến khóa chính, bạn cũng có thể muốn tạo chỉ mục (không duy nhất) cho (các) cột được tham chiếu vì lợi ích của hiệu suất.

Phụ thuộc vào RDBMS bạn đang sử dụng. Tôi nghĩ rằng một số làm điều này cho bạn ngầm, hoặc sử dụng một số thủ thuật khác. RTM.

+0

MySQL (InnoDB) yêu cầu chỉ mục (bên trái) trên cột tham chiếu và tham chiếu. JADP. – chaos

0

Cơ sở dữ liệu nào chúng ta đang nói đến? Trong SQL 2005, tôi không thể tạo ràng buộc khóa ngoài tham chiếu đến một cột không có ràng buộc duy nhất (khóa chính hoặc cách khác).

create table t1 
(
    id int identity, 
    fk int 
); 

create table t2 
(
    id int identity, 
); 

CREATE NONCLUSTERED INDEX [IX_t2] ON [t2] 
(
    [id] ASC 
); 
ALTER TABLE t1 with NOCHECK 
ADD CONSTRAINT FK_t2 FOREIGN KEY (fk) 
    REFERENCES t2 (id) ; 


Msg 1776, Level 16, State 0, Line 1 
There are no primary or candidate keys in the referenced table 't2' 
that match the referencing column list in the foreign key 'FK_t2'. 
Msg 1750, Level 16, State 0, Line 1 
Could not create constraint. See previous errors. 

Nếu bạn thực sự có thể làm điều này, bạn sẽ có mối quan hệ nhiều-nhiều, điều này là không thể nếu không có bảng trung gian. Tôi thực sự muốn nghe thêm về điều này ...

Xem this related question và câu trả lời là tốt.

+0

Tôi đang sử dụng MySQL. – allyourcode

+0

@allyourcode: bạn có nhớ chia sẻ những gì 2 bảng này làm trong cơ sở dữ liệu của bạn có mối quan hệ m nước ngoài m: n này không? – cdonner

2

Khi điều này xảy ra, điều này thường có nghĩa là hai khóa ngoại đang được liên kết với nhau. Thường thì bảng có chứa khóa như khóa chính không phải là ngay cả trong lược đồ.

Ví dụ: Hai bảng, COLLEGES và STUDENTS, cả hai đều chứa một cột có tên là ZIPCODE.

Nếu chúng ta làm một kiểm tra nhanh chóng trên

SELECT * FROM COLLEGES JOIN STUDENTS ON COLLEGES.ZIPCODE = STUDENTS.ZIPCODE 

Chúng ta có thể khám phá ra rằng mối quan hệ là nhiều nhiều. Nếu lược đồ của chúng tôi có một bảng có tên là ZIPCODES, với mã ZIPCODE chính, nó sẽ hiển nhiên những gì đang diễn ra.

Nhưng lược đồ của chúng tôi không có bảng như vậy. Chỉ vì lược đồ của chúng tôi không có bảng như vậy không có nghĩa là dữ liệu đó không tồn tại. một nơi nào đó, trên đất của USPO, chỉ có một cái bàn như vậy. Và cả COLLEGES.ZIPCODE và STUDENTS.ZIPCODE đều là tham chiếu đến bảng đó, ngay cả khi chúng tôi không thừa nhận nó. Điều này có liên quan nhiều hơn đến triết lý dữ liệu hơn là thực hành xây dựng cơ sở dữ liệu, nhưng nó minh họa rõ ràng một điều cơ bản: dữ liệu có những đặc điểm mà chúng ta khám phá và không chỉ những đặc điểm mà chúng ta phát minh ra. Tất nhiên, những gì chúng ta khám phá có thể là những gì người khác phát minh ra. Đó chắc chắn là trường hợp với ZIPCODE.

+0

Bạn đã đánh mất tôi ở "hai khóa ngoại quốc đang được liên kết với nhau". Tôi thực sự không biết điều đó có thể có ý nghĩa gì. – allyourcode

1

PostgreSQL cũng từ chối này (dù sao, ngay cả khi nó là thể, nó không có nghĩa nó là một ý tưởng tốt):

essais=> CREATE TABLE Cities (name TEXT, country TEXT); 
CREATE TABLE 
essais=> INSERT INTO Cities VALUES ('Syracuse', 'USA'); 
INSERT 0 1 
essais=> INSERT INTO Cities VALUES ('Syracuse', 'Greece'); 
INSERT 0 1 
essais=> INSERT INTO Cities VALUES ('Paris', 'France'); 
INSERT 0 1 
essais=> INSERT INTO Cities VALUES ('Aramits', 'France'); 
INSERT 0 1 
essais=> INSERT INTO Cities VALUES ('Paris', 'USA'); 
INSERT 0 1 

essais=> CREATE TABLE People (name TEXT, city TEXT REFERENCES Cities(name)); 
ERROR: there is no unique constraint matching given keys for referenced table "cities" 
+0

Điều này không được đề cập. Và, vì MySQL đặc biệt cẩu thả trong các kiểm tra, ràng buộc và điều khiển, nó sẽ không làm tôi ngạc nhiên rằng tham chiếu toàn vẹn tới các khóa không phải là duy nhất có thể với MySQL. – bortzmeyer

+0

Tôi không nghĩ rằng nó phải làm với việc cẩu thả. Postgresql có chức năng này trong từ khóa 'MATCH PARTIAL', nó không được cài đặt. –

0

Necromancing.
Như những người khác đã nói, bạn không nên tham chiếu khóa không phải là duy nhất làm khóa ngoại.
Nhưng những gì bạn có thể làm thay vào đó (không xóa nguy hiểm thác) đang thêm một ràng buộc kiểm tra (ít nhất là trong MS-SQL).
Đó không chính xác giống như một khóa ngoại, nhưng ít nhất nó sẽ ngăn chặn việc chèn dữ liệu không hợp lệ/mồ côi/chết.

Xem ở đây để tham khảo (bạn sẽ phải cổng mã MS-SQL cú pháp MySQL):
Foreign Key to non-primary key

Edit:
Đang tìm kiếm các lý do downvote, theo Mysql CHECK Constraint, MySQL không thực sự hỗ trợ các ràng buộc CHECK.
Bạn có thể xác định chúng trong truy vấn DDL bạn vì lý do tương thích, nhưng họ chỉ bỏ qua ...

Nhưng như đã đề cập ở đó, bạn có thể tạo một BEFORE INSERTBEFORE UPDATE kích hoạt, nó sẽ ném ra một lỗi khi các yêu cầu của dữ liệu không được đáp ứng, về cơ bản là giống nhau, ngoại trừ việc đó là một mớ hỗn độn lớn hơn.

Đối với câu hỏi:

Tôi nghĩ một chìa khóa nước ngoài có nghĩa là một hàng duy nhất phải tham khảo một hàng duy nhất , nhưng tôi nhìn vào một số bảng, nơi này chắc chắn là không phải như vậy.

Trong bất kỳ RDBMS lành mạnh nào, điều này đúng.
Thực tế là điều này có thể xảy ra trong MySQL chỉ là một lý do nữa tại sao
MySQL là một RDBMS vô hướng.
Nó có thể nhanh, nhưng hy sinh tính toàn vẹn tham chiếu và chất lượng dữ liệu trên bàn thờ tốc độ không phải là ý tưởng của tôi về chất lượng-rdbms.
Trong thực tế, nếu nó không tuân thủ ACID, nó không thực sự là một (đúng chức năng) RDBMS ở tất cả.

+0

InnoDB là [rất gần với tuân thủ ACID] ​​(http://dev.mysql.com/doc/refman/5.7/en/mysql-acid.html). IMHO, đủ gần cho hầu hết các ứng dụng. Và nó cung cấp tăng hiệu suất với MyISAM khi bạn không thực sự cần một cơ sở dữ liệu tuân thủ ACID. Nó là một rdbms chất lượng, nhưng phải mất một DBA tốt để biết khi nào nó là sự lựa chọn tốt nhất. – GabrielF

Các vấn đề liên quan