Tôi có thể có khóa ngoại tham chiếu đến một cột trong dạng xem trong SQL Server không?


84

Trong SQL Server 2008 và được

TableA(A_ID, A_Data)
TableB(B_ID, B_Data)
ViewC(A_or_B_ID, A_or_B_Data)

là nó có thể xác định TableZ(A_or_B_ID, Z_Data)như vậy rằng Z.A_or_B_IDcột bị hạn chế các giá trị được tìm thấy trong ViewCkhông? Điều này có thể được thực hiện với một khóa ngoại đối với chế độ xem không?

Câu trả lời:


108

Bạn không thể tham chiếu chế độ xem trong khóa ngoại.


36
Đây có phải là một hạn chế của máy chủ SQL hay nó là một điều bất hợp lý khi muốn?
Aaron Anodide

1
@Brian Tôi cũng muốn biết liệu đây có phải là hạn chế của SQL Server hay là điều không hợp lý khi muốn bởi vì tại thời điểm này, tôi sắp mô phỏng một chế độ xem bằng cách sử dụng trình kích hoạt chỉ để được hỗ trợ FK (mặc dù tôi đang sử dụng MySql ).
Xe trượt

4
Đây là câu trả lời hay cho những câu hỏi tiếp theo này - stackoverflow.com/questions/3833150/…
Chris Halcrow

Tôi không chắc đó là câu trả lời tốt cho những câu hỏi đó như thế nào ... đó là về một DBMS khác và nói rằng các khung nhìn được thiết kế để ẩn chi tiết lược đồ và thuận tiện cho người dùng. Đầu tiên, ok ... nhưng đây không phải là điều đầu tiên tìm thấy các trường hợp sử dụng vững chắc ngoài thiết kế ban đầu. Thứ hai, tôi không chắc tại sao FK lại không làm như vậy. Một khung nhìn có thể là bất kỳ truy vấn nào mà nó thậm chí không cần phải vẽ ra khỏi bảng, nó có thể là một loạt các hằng số được kết hợp với nhau ... một khóa ngoại có vẻ khá hợp lý trong trường hợp đó. Nếu có lý do tại sao tôi không hy vọng điều gì đó sâu sắc hơn.
George Mauer

27

Trong các phiên bản SQL Server cũ hơn, khóa ngoại chỉ có thể thực hiện được thông qua trình kích hoạt. Bạn có thể bắt chước khóa ngoại tùy chỉnh bằng cách tạo trình kích hoạt Chèn để kiểm tra xem giá trị được chèn có xuất hiện trong một trong các bảng có liên quan hay không.


3
chào mừng bạn đến với StackOverflow. Tôi tìm thấy giá trị trong câu trả lời của bạn vì cung cấp một giải pháp nhưng câu trả lời đúng là câu trả lời được chấp nhận và câu hỏi đã hơn 4 năm, vì vậy tôi không bỏ phiếu nhưng không muốn rời khỏi mà không có nhận xét này.
jachguate

16

Nếu bạn thực sự cần A_or_B_IDtrong TableZ, bạn có hai tùy chọn tương tự:

1) Thêm nullable A_IDB_IDcột vào bảng z, tạo A_or_B_IDmột cột được tính toán bằng cách sử dụng ISNULL trên hai cột này và thêm ràng buộc CHECK sao cho chỉ một trong số A_IDhoặc B_IDkhông phải là null

2) Thêm cột TableName vào bảng z, được giới hạn để chứa A hoặc B. Bây giờ tạo A_IDB_IDdưới dạng cột được tính toán, chỉ có giá trị khác rỗng khi bảng thích hợp của chúng được đặt tên (sử dụng biểu thức CASE). Làm cho họ cũng tồn tại

Trong cả hai trường hợp, bây giờ bạn có A_IDB_IDcác cột có thể có khóa ngoại thích hợp cho các bảng cơ sở. Sự khác biệt là các cột được tính toán. Ngoài ra, bạn không cần TableName trong tùy chọn 2 ở trên nếu các miền của 2 cột ID không trùng nhau - miễn là biểu thức chữ hoa của bạn có thể xác định miền nào A_or_B_ID thuộc

(Cảm ơn nhận xét đã sửa định dạng của tôi)


Đặt từ với dấu gạch trong back-ve: A_or_B_ID
Bill Karwin

Tôi đang làm việc để thêm một số tính năng vào hệ thống cũ và đây là một cách tuyệt vời để vá lỗi cũ và mới với nhau. Cảm ơn bạn!
David Gunderson


4

Có một lựa chọn khác. Coi TableA và TableB là các lớp con của một bảng mới được gọi là TablePrime. Điều chỉnh giá trị ID của TableB để chúng không trùng với giá trị ID của TableA. Đặt ID trong TablePrime thành PK và chèn tất cả ID của TableA và TableB (đã điều chỉnh) vào TablePrime. Làm cho TableA và TableB có mối quan hệ FK trên PK của chúng với cùng một ID trong TablePrime.

Bây giờ bạn có mẫu siêu kiểu / kiểu con và có thể tạo các ràng buộc đối với TablePrime (khi bạn muốn -A-hoặc-B ) hoặc một trong các bảng riêng lẻ (khi bạn chỉ muốn A hoặc chỉ B ).

Nếu bạn cần biết thêm chi tiết xin vui lòng hỏi. Có những biến thể cho phép bạn đảm bảo A và B loại trừ lẫn nhau hoặc có thể thứ bạn đang làm việc có thể là cả hai cùng một lúc. Tốt nhất nên chính thức hóa điều đó trong FK nếu có thể.


2

Sẽ dễ dàng hơn khi thêm một ràng buộc tham chiếu đến một hàm do người dùng xác định để kiểm tra cho bạn, fCheckIfValueExists (columnValue) trả về true nếu giá trị tồn tại và false nếu không.

Ưu điểm là nó có thể nhận nhiều cột, thực hiện các phép tính với chúng, chấp nhận giá trị rỗng và chấp nhận các giá trị không tương ứng chính xác với khóa chính hoặc so sánh với kết quả của các phép nối.

Nhược điểm là trình tối ưu hóa không thể sử dụng tất cả các thủ thuật khóa ngoại của mình.


1
Nhược điểm là trình tối ưu hóa không thể sử dụng tất cả các thủ thuật khóa ngoại của mình ... ... và chức năng sẽ được chạy cho mọi hàng bạn chèn / cập nhật (vì vậy không quá đẹp cho các bộ).
jimbobmcgee

0

Xin lỗi, theo nghĩa chặt chẽ của từ này, không, bạn không thể đặt khóa ngoại trên các khung nhìn. Đây là lý do tại sao:

InnoDB là công cụ lưu trữ tích hợp duy nhất cho MySQL có các khóa ngoại. Mọi bảng InnoDB sẽ được đăng ký trong information_schema.tables với engine = 'InnoDB'.

Các chế độ xem, trong khi được đăng ký trong information_schema.tables, có một công cụ lưu trữ NULL. Không có cơ chế nào trong MySQL để có khóa ngoại trên bất kỳ bảng nào có công cụ lưu trữ không xác định.

Cảm ơn!


câu hỏi này là về máy chủ sql
George Mauer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.