2010-12-15 73 views
40

我在两个不同的数据库中有两个表。在table1(它在database1中)有一个名为column1的列,它是一个主键。现在在table2(它在databse2中)有一个名为coulmn2的列,我想将它作为外键添加。在两个数据库之间添加外键关系

我尝试添加它,它给了我下面的错误:

Msg 1763, Level 16, State 0, Line 1
Cross-database foreign key references are not supported. Foreign key Database2.table2.

Msg 1750, Level 16, State 0, Line 1
Could not create constraint. See previous errors.

我如何做到这一点,因为表是在不同的数据库。

回答

40

您需要使用触发器跨数据库管理参照约束。


基本上你创建一个插入,更新触发器来验证主键表中的键的存在。如果该键不存在,则恢复插入或更新,然后处理该异常。

实施例:

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 

编辑:只是为了澄清。这不是执行参照完整性的最佳方法。理想情况下,你会希望两个表在同一个分贝,但如果这是不可能的。那么以上是你潜在的工作。

+0

你能用一个例子来解释我吗 – Sam 2010-12-15 16:15:53

+0

同样我也必须创建更新触发器。 – Sam 2010-12-15 16:26:37

+0

@Sam是的......但您可以为插入和更新创建一个触发器。看到我编辑的答案 – 2010-12-15 16:29:01

0

如错误消息所示,这在sql server上不受支持。 确保反思正直的唯一方法是与触发器一起工作。

+0

你能用一个例子来解释我吗 – Sam 2010-12-15 16:20:18

3

简而言之,SQL Server(自SQL 2008起)不支持跨数据库外键 - 如错误消息所述。

尽管您不能拥有声明性参照完整性(FK),但您可以使用触发器达到相同的目标。这是不太可靠的,因为你写的逻辑可能有错误,但它会让你在那里一样。

请参阅SQL文档@http://msdn.microsoft.com/en-us/library/aa258254%28v=sql.80%29.aspx哪个州:

Triggers are often used for enforcing business rules and data integrity. SQL Server provides declarative referential integrity (DRI) through the table creation statements (ALTER TABLE and CREATE TABLE); however, DRI does not provide cross-database referential integrity. To enforce referential integrity (rules about the relationships between the primary and foreign keys of tables), use primary and foreign key constraints (the PRIMARY KEY and FOREIGN KEY keywords of ALTER TABLE and CREATE TABLE). If constraints exist on the trigger table, they are checked after the INSTEAD OF trigger execution and prior to the AFTER trigger execution. If the constraints are violated, the INSTEAD OF trigger actions are rolled back and the AFTER trigger is not executed (fired).

还有一个OK讨论过在SQLTeam - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=31135

22

如果您需要坚如磐石的完整性,必须在一个数据库中两个表,并使用FK约束。如果您的父表位于另一个数据库中,则不会阻止任何人从旧备份中还原该父数据库,然后就会产生孤儿。

这就是为什么不支持数据库之间的FK。

20

根据我的经验,当相关的两个表的主要权威信息源必须位于两个单独的数据库中时,处理此问题的最佳方法是将表的副本从主位置同步到次位置(使用T-SQL或SSIS进行适当的错误检查 - 当它有外键引用时,不能截断和重新填充表,因此有几种方法可以更新表上的cat)。

然后在第二个位置添加一个传统的FK关系到表,这是一个只读副本。

您可以在主位置使用触发器或计划作业来更新副本。

+0

Re。 “您可以在主要位置触发或计划作业以保持副本更新”:为什么不使用SQL Server复制(特别是事务与合并类型,因为订户的副本(具有需要外键约束的表副本)只是需要是只读的)?请参阅:[链接](https://docs.microsoft.com/en-us/sql/relational-databases/replication/sql-server-replication) – Tom 2017-04-19 22:00:23

+0

@Tom是的,你当然可以使用复制来保留副本表在远程数据库中更新。 – 2017-04-20 01:15:28

11

您可以使用检查约束与用户定义函数进行检查。它比触发器更可靠。它可以被禁用并在必要时重新启用,与外键相同,并在数据库2恢复后重新检查。

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)