我正在尝试使用为学校项目设置数据库,我正在使用触发器为一个表设置参照完整性。我有一个表,地址,存储人员,工作室和董事的地址。然后我有一个名为Address Reference的表。此表指向Address表,它有两个字段,ReferenceID和TableName,用于显示此地址所用的表和行。我有一个约束因此TableName将始终有效。
我正在尝试设置触发器以确保插入的任何行都有效,我可以这样做,我只是想改进它。我的代码看起来像这样:
SELECT *
FROM inserted
WHERE ReferenceID IN
(SELECT PersonID
FROM inserted.TableName)
但是我发现我需要使用动态sql。所以我在想这样的事情:
SELECT *
FROM inserted
WHERE ReferenceID IN
(EXEC('SELECT PersonID FROM' + inserted.TableName))
即使我删除了执行官,这也行不通。
我在使用SQL Server 11.0.3128的SQL Server Management Studio中执行此操作
如果您需要更多信息,请与我们联系。我环顾四周,但我没有找到任何有效的问题的答案。
答案 0 :(得分:1)
这是维护参照完整性的一种糟糕方式。有很多方法可以解决这个问题。
第一个是拥有地址表,然后是多个表来包含链接,例如
CREATE TABLE StudioAddress
( StudioID INT NOT NULL,
AddressID INT NOT NULL,
CONSTRAINT PK_StudioAddress__StudioID_AddressID PRIMARY KEY (StudioID, AddressID),
CONSTRAINT FK_StudioAddress__StudioID FOREIGN KEY (StudioID) REFERENCES Studio (StudioID),
CONSTRAINT FK_StudioAddress__AddressID FOREIGN KEY (AddressID) REFERENCES Address (AddressID)
);
这可以在不需要触发器的情况下保持您的参考完整性,并且仍然可以满足1对多的关系。
另一种选择是在地址表(StudioID,PersonID,DirectorID)中有3个可为空的列,每个列都有相关表的外键,你可以添加一个检查约束来确保3个字段中只有一个是填充(如果需要)。
我更喜欢第一个选项,它更干净,并且允许将相同的地址用于多个事物。
<强> ADENDUM 强>
如果 使用触发器完成,那么我认为你需要使用这样的东西:
IF EXISTS( SELECT 1
FROM inserted i
WHERE NOT EXISTS
( SELECT 1
FROM People p
WHERE p.PersonID = i.ReferenceID
AND i.TableName = 'People'
UNION ALL
SELECT 1
FROM Studios s
WHERE s.StudioID = i.ReferenceID
AND i.TableName = 'Studios'
UNION ALL
SELECT 1
FROM Directors d
WHERE d.DirectorID = i.ReferenceID
AND i.TableName = 'Directors'
)
)
BEGIN
ROLLBACK TRANSACTION;
RAISERROR('Referential integrity error', 16, 1);
END
这基本上会检查所有插入/更新的行是否存在相关表中相关ID的记录。
我仍然支持我之前的回答,这是一种可怕的方法,我会质疑任何教学大纲!