Thêm mối quan hệ Khoá ngoại giữa hai Cơ sở dữ liệu


90

Tôi có hai bảng trong hai cơ sở dữ liệu khác nhau. Trong table1 (trong database1) có một cột được gọi là column1 và nó là một khóa chính. Bây giờ trong table2 (trong database2) có một cột được gọi là column2 và tôi muốn thêm nó làm khóa ngoại.

Tôi đã cố gắng thêm nó và nó gây ra lỗi sau:

Msg 1763, Mức 16, Trạng thái 0, Dòng 1
Tham chiếu khóa ngoại cơ sở dữ liệu chéo không được hỗ trợ. Khoá ngoại Cơ sở dữ liệu2.table2.

Msg 1750, Mức 16, Trạng thái 0, Dòng 1
Không thể tạo ràng buộc. Xem các lỗi trước đó.

Làm cách nào để làm điều đó vì các bảng nằm trong các cơ sở dữ liệu khác nhau.

Câu trả lời:


84

Bạn sẽ cần quản lý ràng buộc tham chiếu giữa các cơ sở dữ liệu bằng cách sử dụng Trigger.


Về cơ bản, bạn tạo một trình kích hoạt chèn, cập nhật để xác minh sự tồn tại của Khóa trong bảng Khóa chính. Nếu khóa không tồn tại thì hoàn nguyên chèn hoặc cập nhật rồi xử lý ngoại lệ.

Thí dụ:

Create Trigger dbo.MyTableTrigger ON dbo.MyTable, After Insert, Update
As
Begin

   If NOT Exists(select PK from OtherDB.dbo.TableName where PK in (Select FK from inserted) BEGIN
      -- Handle the Referential Error Here
   END

END

Đã chỉnh sửa: Chỉ để làm rõ. Đây không phải là cách tiếp cận tốt nhất để thực thi tính toàn vẹn tham chiếu. Lý tưởng nhất là bạn muốn cả hai bảng trong cùng một db nhưng nếu điều đó là không thể. Sau đó, ở trên là một công việc tiềm năng xung quanh bạn.


3
@John Hartsock - ví dụ trên có thể dễ dàng thất bại nếu không thêm xử lý giao dịch thích hợp. Một cuộc thảo luận đàng hoàng của các loại vấn đề có thể xảy ra với "nếu không tồn tại () sau đó chèn" có thể được tìm thấy ở đây - stackoverflow.com/questions/108403/...
EBarr

16
@John Hartsock - giải pháp của bạn có một lỗ hổng: nếu một trong hai cơ sở dữ liệu được khôi phục từ bản sao lưu, thì tất nhiên các trình kích hoạt sẽ không kích hoạt. Đây là cách chúng ta có thể kết thúc với hàng mồ côi.
AK

4
@AlexKuznetsov Chính xác. Như tôi đã giải thích, đây không phải là cách tiếp cận tốt nhất mà là một công việc tiềm năng.
John Hartsock

2
Điều này thật sai lầm ... Tôi chỉ hy vọng OP nhận ra rằng việc anh ấy đang hỏi điều gì đó như thế này, là một dấu hiệu cho thấy anh ấy rất có thể đã làm sai điều gì đó ... hãy nghĩ đến việc kích hoạt ..
MeTitus

1
@Marco Như tôi đã đăng trong câu trả lời của mình "Chỉ cần làm rõ. Đây không phải là cách tiếp cận tốt nhất để thực thi tính toàn vẹn tham chiếu. Lý tưởng nhất là bạn muốn cả hai bảng trong cùng một db nhưng nếu điều đó là không thể. Ở trên là một công việc tiềm năng xung quanh bạn." Tôi giải thích rằng đây có lẽ không phải là một ý kiến ​​hay.
John Hartsock

48

Nếu bạn cần tính toàn vẹn vững chắc, hãy có cả hai bảng trong một cơ sở dữ liệu và sử dụng ràng buộc FK. Nếu bảng cha của bạn nằm trong cơ sở dữ liệu khác, không có gì ngăn cản bất kỳ ai khôi phục cơ sở dữ liệu mẹ đó từ một bản sao lưu cũ, và khi đó bạn có trẻ mồ côi.

Đây là lý do tại sao FK giữa các cơ sở dữ liệu không được hỗ trợ.


27

Theo kinh nghiệm của tôi, cách tốt nhất để xử lý điều này khi nguồn thông tin có thẩm quyền chính cho hai bảng có liên quan phải nằm trong hai cơ sở dữ liệu riêng biệt là đồng bộ hóa bản sao của bảng từ vị trí chính sang vị trí phụ (sử dụng T- SQL hoặc SSIS với tính năng kiểm tra lỗi thích hợp - bạn không thể cắt bớt và tạo lại một bảng trong khi nó có tham chiếu khóa ngoại, vì vậy có một số cách để cập nhật da mèo trên bảng).

Sau đó, thêm mối quan hệ FK truyền thống ở vị trí thứ hai vào bảng, đây là một bản sao chỉ đọc.

Bạn có thể sử dụng trình kích hoạt hoặc công việc đã lên lịch ở vị trí chính để cập nhật bản sao.


1
Re. "Bạn có thể kích hoạt hoặc lập lịch công việc ở vị trí chính để giữ cho bản sao được cập nhật": Tại sao không chỉ sử dụng SQL Server Replication (cụ thể là loại Giao dịch so với Hợp nhất vì bản sao của Người đăng ký (bản sao có Bảng cần Ràng buộc khóa ngoại) chỉ cần ở chế độ chỉ đọc)? Xem: liên kết
Tom

@Tom vâng, bạn chắc chắn có thể sử dụng bản sao để giữ bản sao của bảng được cập nhật trong cơ sở dữ liệu từ xa.
Cade Roux

20

Bạn có thể sử dụng ràng buộc kiểm tra với một hàm do người dùng xác định để thực hiện kiểm tra. Nó đáng tin cậy hơn một kích hoạt. Nó có thể bị vô hiệu hóa và kích hoạt lại khi cần thiết giống như khóa ngoài và được kiểm tra lại sau khi khôi phục database2.

CREATE FUNCTION dbo.fn_db2_schema2_tb_A
(@column1 INT) 
RETURNS BIT
AS
BEGIN
    DECLARE @exists bit = 0
    IF EXISTS (
      SELECT TOP 1 1 FROM DB2.SCHEMA2.tb_A 
      WHERE COLUMN_KEY_1 =  @COLUMN1
    ) BEGIN 
         SET @exists = 1 
      END;
      RETURN @exists
END
GO

ALTER TABLE db1.schema1.tb_S
  ADD CONSTRAINT CHK_S_key_col1_in_db2_schema2_tb_A
    CHECK(dbo.fn_db2_schema2_tb_A(key_col1) = 1)

1
đây là một giải pháp tốt hơn so với câu trả lời được chấp nhận và bạn cũng có thể tái sử dụng nó trên nhiều bảng
Milox

3

Câu trả lời ngắn gọn là SQL Server (kể từ SQL 2008) không hỗ trợ các khóa ngoại cơ sở dữ liệu chéo - như thông báo lỗi nêu rõ.

Mặc dù bạn không thể có tính toàn vẹn tham chiếu khai báo (FK), bạn có thể đạt được mục tiêu tương tự bằng cách sử dụng trình kích hoạt. Nó kém tin cậy hơn một chút, bởi vì logic bạn viết có thể có lỗi, nhưng nó sẽ giúp bạn đạt được điều đó.

Xem tài liệu SQL @ http://msdn.microsoft.com/en-us/library/aa258254%28v=sql.80%29.aspx Trạng thái nào:

Trình kích hoạt thường được sử dụng để thực thi các quy tắc kinh doanh và tính toàn vẹn của dữ liệu. SQL Server cung cấp tính toàn vẹn tham chiếu khai báo (DRI) thông qua các câu lệnh tạo bảng (ALTER TABLE và CREATE TABLE); tuy nhiên, DRI không cung cấp tính toàn vẹn tham chiếu cơ sở dữ liệu chéo. Để thực thi tính toàn vẹn tham chiếu (các quy tắc về mối quan hệ giữa khóa chính và khóa ngoại của bảng), hãy sử dụng ràng buộc khóa chính và khóa ngoại (từ khóa PRIMARY KEY và FOREIGN KEY của ALTER TABLE và CREATE TABLE). Nếu các ràng buộc tồn tại trên bảng kích hoạt, chúng sẽ được kiểm tra sau khi thực thi kích hoạt INSTEAD OF và trước khi thực hiện kích hoạt SAU. Nếu các ràng buộc bị vi phạm, các hành động kích hoạt INSTEAD OF sẽ được khôi phục và trình kích hoạt SAU sẽ không được thực thi (được kích hoạt).

Cũng có một cuộc thảo luận OK tại SQLTeam - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=31135


0

Như thông báo lỗi cho biết, điều này không được hỗ trợ trên máy chủ sql. Cách duy nhất để đảm bảo tính toàn vẹn theo cấp số nhân là làm việc với các trình kích hoạt.


1
Bạn có thể giải thích cho tôi với một ví dụ
Sam
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.