SQL脚本根据依赖项替换所有FK值?它甚至可能吗?

时间:2014-11-18 06:44:44

标签: sql-server tsql

假设我想要合并两个用户(即需要删除用户。在此之前更新该用户与其他用户的所有引用)。 我想用新用户ID替换要删除的用户的所有引用。 通过获取该用户表的依赖关系,是否可以使用任何sql脚本执行此操作?

[更新] 我正在寻找一个自动识别依赖关系并交换用户ID的脚本

3 个答案:

答案 0 :(得分:0)

是的,如果您可以先创建新用户,并在插入后,根据条件更新参考。

declare @newUserid int , @olduserid
insert user values (colval1, colval2,..)

select @newUserid = @@identity

update tablename set userid = @newUserid where userid = @olduserid

如果是多个用户,则为更新语句创建动态查询。

Declare @query nvarchar(max)

Set @query = 'update tablename set userid = ' + @newUserid + ' where userid in ( ' + @olduserid + ')'

EXEC sp_executesql @query

最后,您可以删除用户。

<强>更新 对于自动配合进程,您使用Sql Jobs或使用触发器。您可以安排Sqljob,而只要插入,更新,删除发生,就会在表上触发触发器。

所以触发器的缺点是性能观点,而对于sql-job,你需要sqlagent功能,这在sqlserver enterprice版或者equilant中可用,快递版没有Sqlagent。

我建议,无论何时插入或更新,您都可以使用或说出另一个程序,根据当前的方案更新记录。

如果userid = 1或者usertype =&#39; guest&#39;则不会向我们提供任何方案。更新,然后更改数据等。

答案 1 :(得分:0)

Cascade Update中有一些名为SQL SERVER的内容。 ON UPDATE CASCADE选项指定如果尝试更新行中的键值,其中键值由其他表中现有行中的外键引用,则所有外键值也会更新为为密钥指定的新值。如果还在目标表上定义了级联引用操作,则还会对这些表中更新的键值采取指定的级联操作

检查 here 了解更多信息

ALTER TABLE childtablename
  ADD CONSTRAINT FK_name FOREIGN KEY(childcolumn) REFERENCES parenttable (parentcolumn) ON  UPDATE  CASCADE 

答案 2 :(得分:0)

是的,可以通过编程方式识别表的依赖关系(外键约束)。 您需要的是sys-Tables

特别需要:

  • sys.all_objects(获取表名)
  • sys.foreign_key_columns(获取您要查找的外键)
  • sys.columns(获取相关列的名称)

考虑到这一点

SELECT
        ReferencedTable.name AS ReferencedTableName,
        ReferencedColumn.name AS ReferencedColumnName,
        DependingTable.name AS DependingTableName,
        DependingColumn.name AS DependingColumnName
    FROM sys.all_objects AS DependingTable
    INNER JOIN sys.foreign_key_columns AS ForeignKeys
        ON DependingTable.object_id = ForeignKeys.parent_object_id
    INNER JOIN sys.all_objects AS ReferencedTable
        ON ForeignKeys.referenced_object_id = ReferencedTable.object_id
    INNER JOIN sys.columns AS DependingColumn
        ON ForeignKeys.parent_object_id = DependingColumn.object_id AND ForeignKeys.parent_column_id = DependingColumn.column_id
    INNER JOIN sys.columns AS ReferencedColumn
        ON ForeignKeys.referenced_object_id = ReferencedColumn.object_id AND ForeignKeys.referenced_column_id = ReferencedColumn.column_id
    WHERE ReferencedTable.name = 'UserTable'

将为您提供一个结果集,每行代表一个现有外键,包含您引用的表名,引用的列名,当然还有依赖(引用)表及其列的名称。现在我们可以更进一步:

鉴于您知道将删除哪个用户ID以及哪个id将作为替代,您可以让最后一个查询为您生成更新语句,以下代码就是这样做的,并且最重要的是使用游标立即执行这些陈述(您只需要设置@tableName@sourceValue@targetValue):

DECLARE @tableName NVARCHAR(MAX) = 'UserTable'
DECLARE @sourceValue INT = 3
DECLARE @targetValue INT = 1

DECLARE @sqlStatements TABLE (ID INT PRIMARY KEY IDENTITY(1,1), cmdTxt NVARCHAR(MAX))

INSERT @sqlStatements (cmdTxt)
    SELECT
            'UPDATE ' + DependingTable.name + ' SET ' + DependingColumn.name + ' = ' + CAST(@targetValue AS NVARCHAR(MAX)) +
            ' WHERE ' + DependingColumn.name + ' = ' + CAST(@sourceValue AS NVARCHAR(MAX))
        FROM sys.all_objects AS DependingTable
        INNER JOIN sys.foreign_key_columns AS ForeignKeys
            ON DependingTable.object_id = ForeignKeys.parent_object_id
        INNER JOIN sys.all_objects AS ReferencedTable
            ON ForeignKeys.referenced_object_id = ReferencedTable.object_id
        INNER JOIN sys.columns AS DependingColumn
            ON ForeignKeys.parent_object_id = DependingColumn.object_id AND ForeignKeys.parent_column_id = DependingColumn.column_id
        INNER JOIN sys.columns AS ReferencedColumn
            ON ForeignKeys.referenced_object_id = ReferencedColumn.object_id AND ForeignKeys.referenced_column_id = ReferencedColumn.column_id
        WHERE ReferencedTable.name = @tableName

DECLARE @currentCmd NVARCHAR(MAX)

DECLARE cmd_cursor CURSOR FOR
    SELECT cmdTxt FROM @sqlStatements ORDER BY ID ASC

OPEN cmd_cursor
FETCH NEXT FROM cmd_cursor 
INTO @currentCmd

WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC sp_executesql @currentCmd

    FETCH NEXT FROM cmd_cursor 
    INTO @currentCmd
END 
CLOSE cmd_cursor;
DEALLOCATE cmd_cursor;

您可能应该在事务中封装整个事情并在最后做一些令人安慰的select语句,告诉您在最终提交更改之前没有破坏任何内容。