【问题标题】:Add Foreign Key relationship between two Databases在两个数据库之间添加外键关系
【发布时间】:2011-05-26 00:38:01
【问题描述】:

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

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

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

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

由于表位于不同的数据库中,我该怎么做。

【问题讨论】:

    标签: sql sql-server tsql foreign-keys


    【解决方案1】:

    您可以将检查约束与用户定义的函数一起使用来进行检查。它比触发器更可靠。它可以像外键一样在必要时禁用和重新启用,并在 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)
    

    【讨论】:

    • 这是一个比公认答案更好的解决方案,您还可以在多个表上重复使用它
    【解决方案2】:

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


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

    例子:

    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
    

    已编辑:只是为了澄清。这不是执行参照完整性的最佳方法。理想情况下,您希望两个表都在同一个数据库中,但如果这是不可能的。那么以上是您的潜在解决方法。

    【讨论】:

    • @John Hartsock -- 如果不添加适当的事务处理,上述示例很容易失败。可以在这里找到关于“如果不存在()然后插入”可能发生的问题类型的体面讨论 - stackoverflow.com/questions/108403/…
    • @John Hartsock - 你的解决方案有一个漏洞:如果两个数据库之一从备份中恢复,触发器当然不会触发。这就是我们最终得到孤立行的方式。
    • @AlexKuznetsov 没错。正如我所解释的,这不是最好的方法,而是一种潜在的解决方法。
    • 这太错误了......我只是希望OP意识到他要求这样的事情的事实,是他很可能做错事的症状......让单独考虑触发器..
    • @Marco 正如我在我的回答中发布的“只是为了澄清。这不是强制执行参照完整性的最佳方法。理想情况下,您希望两个表都在同一个数据库中,但如果这是不可能的。那么以上是您的潜在解决方法。”我解释说这可能不是一个好主意。
    【解决方案3】:

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

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

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

    【讨论】:

    • 回复。 “您可以在主要位置触发或计划作业以保持副本更新”:为什么不只使用 SQL Server 复制(特别是事务与合并类型,因为订阅者的副本(具有需要外键约束的表的副本)只是需要只读)?见:link
    • @Tom 是的,您当然可以使用复制在远程数据库中更新表的副本。
    【解决方案4】:

    如果您需要坚如磐石的完整性,请将两个表放在一个数据库中,并使用 FK 约束。如果您的父表在另一个数据库中,则没有什么可以阻止任何人从旧备份中恢复该父数据库,然后您就会有孤儿。

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

    【讨论】:

      【解决方案5】:

      简短的回答是 SQL Server(自 SQL 2008 起)不支持跨数据库外键 - 正如错误消息所述。

      虽然您不能拥有声明性参照完整性 (FK),但您可以使用触发器达到相同的目标。它有点不太可靠,因为你编写的逻辑可能有错误,但它会让你达到同样的效果。

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

      触发器通常用于强制执行 业务规则和数据完整性。 SQL 服务器提供声明式 参照完整性 (DRI) 通过 表创建语句(ALTER 表和创建表);然而,DRI 不提供跨数据库 参照完整性。执行 参照完整性(关于 主要和之间的关系 表的外键),使用主键 和外键约束( PRIMARY KEY 和 FOREIGN KEY 关键字 ALTER TABLE 和 CREATE TABLE)。如果 触发器上存在约束 表,他们被检查后 INSTEAD OF 触发器执行和之前 到 AFTER 触发器执行。如果 违反了约束, INSTEAD OF 触发动作被回滚并且 未执行 AFTER 触发器 (被解雇)。

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

      【讨论】:

        【解决方案6】:

        正如错误消息所说,这在 sql server 上不受支持。 确保引用完整性的唯一方法是使用触发器。

        【讨论】:

        • 你能举个例子解释一下吗
        猜你喜欢
        • 1970-01-01
        • 2012-02-26
        • 1970-01-01
        • 2017-09-15
        • 2016-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多