在两个数据库之间添加外键关系

Sam*_*Sam 77 sql t-sql sql-server foreign-keys

我在两个不同的数据库中有两个表.在table1中(在database1中)有一个名为column1的列,它是一个主键.现在在table2(在database2中)有一个名为column2的列,我想将它添加为外键.

我试图添加它,它给了我以下错误:

消息1763,级别16,状态0,行1
不支持跨数据库外键引用.外键Database2.table2.

消息1750,级别16,状态0,行1
无法创建约束.查看以前的错误.

我是如何做到这一点的,因为表位于不同的数据库中.

Joh*_*ock 75

您需要使用Trigger管理跨数据库的引用约束.


基本上,您创建一个insert,update触发器以验证主键表中是否存在Key.如果密钥不存在,则还原插入或更新,然后处理异常.

例:

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
Run Code Online (Sandbox Code Playgroud)

编辑: 只是为了澄清.这不是强制引用完整性的最佳方法.理想情况下,您可能希望同一个数据库中的两个表,但如果这是不可能的.那以上就是你的潜在工作.

  • @John Hartsock - 你的解决方案有一个漏洞:如果从备份中恢复了两个数据库中的一个,触发器当然不会触发.这就是我们最终得到孤儿行的方法. (11认同)
  • @John Hartsock - 上面的例子很容易失败,没有添加适当的事务处理.可以在这里找到关于"如果不存在()然后插入"可能发生的问题类型的正确讨论 - http://stackoverflow.com/questions/108403/solutions-for-insert-or-update-on- SQL服务器/ 108540#108540 (3认同)
  • @AlexKuznetsov完全正确.正如我所解释的那样,这不是最好的方法,而是潜在的解决方法. (3认同)
  • 这太错误了……我只是希望 OP 意识到,他提出这样的问题这一事实,表明他很可能做错了什么……更不用说考虑触发器了。 (2认同)
  • @Marco 正如我在我的回答中发布的那样“只是为了澄清。这不是强制引用完整性的最佳方法。理想情况下,您希望两个表位于同一个数据库中,但如果这是不可能的。那么上面的方法是一个潜在的解决方法你。” 我解释说这可能不是一个好主意。 (2认同)

A-K*_*A-K 42

如果您需要坚如磐石的完整性,请在一个数据库中同时使用两个表,并使用FK约束.如果您的父表位于另一个数据库中,则没有任何东西阻止任何人从旧备份恢复该父数据库,然后您有孤儿.

这就是不支持数据库之间的FK的原因.


Cad*_*oux 25

根据我的经验,当相关的两个表的主要权威信息源必须位于两个单独的数据库中时,处理此问题的最佳方法是将表的副本从主位置同步到辅助位置(使用T- SQL或SSIS与相应的错误检查 - 你不能截断并重新填充表,同时它有一个外键引用,所以有到皮表上的更新猫)的几种方法.

然后在第二个位置将一个传统的FK关系添加到表中,该表实际上是一个只读副本.

您可以在主位置使用触发器或预定作业来更新副本.

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

小智 18

您可以使用带有用户定义函数的检查约束来进行检查.它比触发器更可靠.它可以在必要时与外键一起禁用和重新启用,并在数据库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)
Run Code Online (Sandbox Code Playgroud)

  • 这是比接受的答案更好的解决方案,您也可以在多个表上重复使用它 (3认同)