我在两个不同的数据库中有两个表。在table1中(在database1中)有一个称为column1的列,它是主键。现在在table2中(在database2中)有一个名为column2的列,我想将其添加为外键。
我尝试添加它,它给了我以下错误:
消息1763,级别16,状态0,第1行
不支持跨数据库外键引用。外键Database2.table2。消息1750,级别16,状态0,第1行
无法创建约束。请参阅先前的错误。
由于表位于不同的数据库中,我该怎么办。
Answers:
您将需要使用触发器来管理跨数据库的引用约束。
基本上,您将创建一个插入,更新触发器以验证主键表中是否存在该键。如果密钥不存在,则还原插入或更新,然后处理异常。
例:
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
编辑: 只是为了澄清。这不是强制执行参照完整性的最佳方法。理想情况下,您希望将两个表都放在同一个数据库中,但是那样是不可能的。那么以上是您可能需要解决的问题。
以我的经验,当两个相关表的主要权威信息源必须位于两个单独的数据库中时,处理此问题的最佳方法是将表的副本从主要位置同步到辅助位置(使用T-具有适当错误检查的SQL或SSIS-当表具有外键引用时,您无法截断并重新填充表,因此有几种方法可以在更新表时使用猫。
然后将第二个位置的传统FK关系添加到表中,该关系实际上是只读副本。
您可以在主要位置使用触发器或计划作业,以使副本保持更新。
您可以将检查约束与用户定义的函数配合使用来进行检查。它比触发器更可靠。可以在必要时与外键一样禁用和重新启用它,并在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)
简短的答案是,SQL Server(从SQL 2008开始)不支持跨数据库外键,这是错误消息指出的。
虽然您不能具有声明性参照完整性(FK),但是可以使用触发器来达到相同的目标。它的可靠性稍差一些,因为您编写的逻辑可能存在错误,但可以使您保持一致。
请参阅SQL文档@ http://msdn.microsoft.com/zh-cn/library/aa258254%28v=sql.80%29.aspx哪个状态:
触发器通常用于执行业务规则和数据完整性。SQL Server通过表创建语句(ALTER TABLE和CREATE TABLE)提供声明性引用完整性(DRI)。但是,DRI不提供跨数据库引用完整性。要强制执行引用完整性(关于表的主键和外键之间的关系的规则),请使用主键和外键约束(ALTER TABLE和CREATE TABLE的PRIMARY KEY和FOREIGN KEY关键字)。如果触发器表上存在约束,则在INSTEAD OF触发器执行之后和AFTER触发器执行之前检查约束。如果违反了约束,则会回退INSTEAD OF触发器动作,并且不会执行(触发)AFTER触发器。
在SQLTeam上也可以进行讨论-http://www.sqlteam.com/forums/topic.asp?TOPIC_ID = 31135