SQL Server có phương pháp chọn giữa một chỉ mục duy nhất và khóa chính không?
Ít nhất có thể hướng SqlServer tới khóa chính tham chiếu, khi khóa ngoại được tạo và các ràng buộc khóa thay thế hoặc các chỉ mục duy nhất tồn tại trên bảng được tham chiếu.
Nếu khóa chính cần được tham chiếu, thì chỉ nên chỉ định tên của bảng được tham chiếu trong định nghĩa khóa ngoài và danh sách các cột được tham chiếu nên được bỏ qua:
ALTER TABLE Child
ADD CONSTRAINT FK_Child_Parent FOREIGN KEY (ParentID)
-- omit key columns of the referenced table
REFERENCES Parent /*(ParentID)*/;
Chi tiết bên dưới.
Hãy xem xét các thiết lập sau:
CREATE TABLE T (id int NOT NULL, a int, b int, c uniqueidentifier, filler binary(1000));
CREATE TABLE TRef (tid int NULL);
nơi bảng TRef
dự định tham khảo bảng T
.
Để tạo ràng buộc tham chiếu, người ta có thể sử dụng ALTER TABLE
lệnh với hai lựa chọn thay thế:
ALTER TABLE TRef
ADD CONSTRAINT FK_TRef_T_1 FOREIGN KEY (tid) REFERENCES T (id);
ALTER TABLE TRef
ADD CONSTRAINT FK_TRef_T_2 FOREIGN KEY (tid) REFERENCES T;
lưu ý rằng trong trường hợp thứ hai, không có cột nào của bảng được tham chiếu được chỉ định ( REFERENCES T
so với REFERENCES T (id)
).
Vì chưa có chỉ mục chính T
nào, việc thực thi các lệnh này sẽ phát sinh lỗi.
Lệnh đầu tiên trả về lỗi sau:
Msg 1776, Cấp 16, Bang 0, Dòng 4
Không có khóa chính hoặc khóa ứng cử viên trong bảng được tham chiếu 'T' khớp với danh sách cột tham chiếu trong khóa ngoại 'FK_TRef_T_1'.
Lệnh thứ hai, tuy nhiên, trả về lỗi khác nhau:
Msg 1773, Cấp 16, Bang 0, Dòng 4
Khóa ngoại 'FK_TRef_T_2' có tham chiếu ngầm đến đối tượng 'T' không có khóa chính được xác định trên đó.
thấy rằng trong trường hợp đầu tiên, kỳ vọng là khóa chính hoặc khóa ứng viên , trong khi đó, trường hợp thứ hai chỉ là khóa chính .
Hãy kiểm tra xem SqlServer có sử dụng thứ gì khác ngoài khóa chính với lệnh thứ hai hay không.
Nếu chúng tôi thêm một số chỉ mục duy nhất và khóa duy nhất trên T
:
CREATE UNIQUE INDEX IX_T_1 on T(id) INCLUDE (filler);
CREATE UNIQUE INDEX IX_T_2 on T(id) INCLUDE (c);
CREATE UNIQUE INDEX IX_T_3 ON T(id) INCLUDE (a, b);
ALTER TABLE T
ADD CONSTRAINT UQ_T UNIQUE CLUSTERED (id);
lệnh FK_TRef_T_1
tạo sáng tạo thành công, nhưng lệnh FK_TRef_T_2
tạo sáng tạo vẫn thất bại với Msg 1773.
Cuối cùng, nếu chúng ta thêm khóa chính vào T
:
ALTER TABLE T
ADD CONSTRAINT PK_T PRIMARY KEY NONCLUSTERED (id);
lệnh để FK_TRef_T_2
tạo thành công.
Hãy kiểm tra xem các chỉ mục nào của bảng T
được tham chiếu bởi các khóa ngoại của bảng TRef
:
select
ix.index_id,
ix.name as index_name,
ix.type_desc as index_type_desc,
fk.name as fk_name
from sys.indexes ix
left join sys.foreign_keys fk on
fk.referenced_object_id = ix.object_id
and fk.key_index_id = ix.index_id
and fk.parent_object_id = object_id('TRef')
where ix.object_id = object_id('T');
cái này trả về:
index_id index_name index_type_desc fk_name
--------- ----------- ----------------- ------------
1 UQ_T CLUSTERED NULL
2 IX_T_1 NONCLUSTERED FK_TRef_T_1
3 IX_T_2 NONCLUSTERED NULL
4 IX_T_3 NONCLUSTERED NULL
5 PK_T NONCLUSTERED FK_TRef_T_2
thấy rằng FK_TRef_T_2
tương ứng với PK_T
.
Vì vậy, có, với việc sử dụng REFERENCES T
cú pháp khóa ngoài của TRef
ánh xạ được ánh xạ tới khóa chính của T
.
Tôi không thể tìm thấy hành vi như vậy được mô tả trực tiếp trong tài liệu SqlServer, nhưng Msg 1773 dành riêng cho thấy rằng nó không phải là ngẫu nhiên. Việc triển khai như vậy có thể cung cấp sự tuân thủ với Tiêu chuẩn SQL, bên dưới là đoạn trích ngắn từ phần 11.8 của ANSI / ISO 9075-2: 2003
11 Định nghĩa và thao tác lược đồ
11.8 <định nghĩa ràng buộc tham chiếu>
Chức năng
Chỉ định một ràng buộc tham chiếu.
định dạng
<referential constraint definition> ::=
FOREIGN KEY <left paren> <referencing columns> <right paren>
<references specification>
<references specification> ::=
REFERENCES <referenced table and columns>
[ MATCH <match type> ]
[ <referential triggered action> ]
...
Quy tắc cú pháp
...
3) Trường hợp:
...
b) Nếu <bảng và cột tham chiếu> không chỉ định <danh sách cột tham chiếu>, thì bộ mô tả bảng của bảng được tham chiếu sẽ bao gồm một ràng buộc duy nhất chỉ định KEY PRIMARY. Đặt các cột được tham chiếu là cột hoặc cột được xác định bởi các cột duy nhất trong ràng buộc duy nhất đó và để cột
được tham chiếu là một cột như vậy. <Bảng và cột được tham chiếu> sẽ được xem xét để chỉ định ngầm định <danh sách cột tham chiếu> giống hệt với <danh sách cột duy nhất>.
...
Transact-SQL hỗ trợ và mở rộng ANSI SQL. Tuy nhiên, nó không phù hợp với tiêu chuẩn SQL. Có một tài liệu có tên SQL Server Transact-SQL ISO / IEC 9075-2 Tài liệu hỗ trợ tiêu chuẩn (viết tắt là MS-TSQLISO02, xem tại đây ) mô tả mức độ hỗ trợ được cung cấp bởi Transact-SQL. Tài liệu liệt kê các phần mở rộng và các biến thể theo tiêu chuẩn. Ví dụ, tài liệu đó là MATCH
mệnh đề không được hỗ trợ trong định nghĩa ràng buộc tham chiếu. Nhưng không có biến thể tài liệu liên quan đến phần trích dẫn của tiêu chuẩn. Vì vậy, ý kiến của tôi là hành vi quan sát được ghi lại đủ.
Và với việc sử dụng REFERENCES T (<reference column list>)
cú pháp, có vẻ như SqlServer chọn chỉ mục không bao gồm phù hợp đầu tiên trong số các chỉ mục của bảng được tham chiếu (cái có ít nhất index_id
, không phải là cái có kích thước vật lý nhỏ nhất như được giả định trong các câu hỏi) hoặc chỉ mục được nhóm phù hợp và không có chỉ số không bao gồm phù hợp. Hành vi như vậy có vẻ phù hợp kể từ SqlServer 2008 (phiên bản 10.0). Đây chỉ là quan sát tất nhiên, không có đảm bảo trong trường hợp này.