使用列名称指定预定义的表

时间:2013-12-04 18:08:58

标签: sql sql-server dynamic-sql

我正在尝试使用为学校项目设置数据库,我正在使用触发器为一个表设置参照完整性。我有一个表,地址,存储人员,工作室和董事的地址。然后我有一个名为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中执行此操作

如果您需要更多信息,请与我们联系。我环顾四周,但我没有找到任何有效的问题的答案。

1 个答案:

答案 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的记录。

我仍然支持我之前的回答,这是一种可怕的方法,我会质疑任何教学大纲!