如何将关联表中的所有Id值(通过外键)更新为另一个值?

时间:2014-06-03 17:14:32

标签: sql-server entity-framework tsql

这个问题可能看起来有点奇怪。但让我解释一下我的真正问题。

在我的系统中,有建筑数据,用户可以自由地向系统添加数据。稍后将审核所有用户数据。有时,用户将建筑物A添加为“Foo A”。有时,他们将其添加为“Foo bar A”。这两个记录都指的是同一个真实世界的对象。

对于管理员,他们需要检查所有输入数据,并用正确的替换所有无效。但是,在用户添加新建筑物之后。他们还在其他表中使用这个新建筑,如“订单”表。

enter image description here

我需要一些SQL脚本(SQL Server 2008或更高版本)来使用新数据更新所有关联数据。之后,我可以安全地从数据库中删除无效数据。

谢谢,

PS.1我有这么多表。我无法为每个表手动编写一些脚本。

PS.2关联表中的列名可能不是“BuildingId”,因此我们不能使用“BuildingId”作为搜索条件来查找关联表。

2 个答案:

答案 0 :(得分:2)

假设依赖表'字段名称将始终包含 BuildingID,您可以使用动态SQL来构建更新语句,然后将它们粘贴到新的代码窗口中:

USE DatabaseName

DECLARE @OldBuildingID INT = 123
DECLARE @NewBuildingID INT = 456

select 'UPDATE DatabaseName.dbo.' + columns.TABLE_NAME + ' SET ' + columns.column_name +' = ' + CAST(@NewBuildingID AS VARCHAR(10))  + ' WHERE ' + columns.column_name + ' = ' + CAST(@OldBuildingID AS VARCHAR(10)) + ';' AS SQLDeleteStatement
from information_schema.COLUMNS columns
INNER JOIN sys.objects tables ON columns.TABLE_NAME = tables.name
where columns.COLUMN_NAME like '%BuildingID%'
AND tables.[type] = ( 'U' )

答案 1 :(得分:1)

对于此示例,我尝试删除系统的用户。但是,此用户已从许多其他表中引用。我需要将其他表中的所有引用值更新为新值。

首先,我声明一些变量以保留所有参数。

DECLARE @sql nvarchar (255);
DECLARE @refTableName varchar(255) = 'User'
DECLARE @refColName varchar(255) = 'Id'
DECLARE @refValue uniqueidentifier = '2a8a0f61-fe5c-4dd7-8e6d-00c8340333c4'

-- Deleted User Key
DECLARE @refNewValue uniqueidentifier = '99999999-9999-9999-9999-999999999999'

其次,我通过FOREIGN KEY约束查询所有引用的列/表。

DECLARE RelatedTableCursor CURSOR 
  LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT
    result.TableName,
    result.ColumnName
FROM
(
    SELECT
        OBJECT_NAME(f.parent_object_id) AS TableName,
        COL_NAME(fc.parent_object_id,fc.parent_column_id) AS ColumnName,
        SCHEMA_NAME(o.SCHEMA_ID) ReferenceSchemaName,
        OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
        COL_NAME(fc.referenced_object_id,fc.referenced_column_id) AS ReferenceColumnName
    FROM sys.foreign_keys AS f
    INNER JOIN sys.foreign_key_columns AS fc ON f.OBJECT_ID = fc.constraint_object_id
    INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id
) result
WHERE
    ReferenceTableName = @refTableName AND ReferenceColumnName = @refColName

接下来,我将所有引用的值更改为新值。

OPEN RelatedTableCursor
WHILE 1 = 1
BEGIN 
    DECLARE @tableName varchar(255)
    DECLARE @columnName varchar(255)

    FETCH NEXT FROM RelatedTableCursor into @tableName, @columnName

    IF @@fetch_status <> 0
    BEGIN
        BREAK
    END

    DECLARE @sql nvarchar (255);
    SET @sql = 
        N'UPDATE [' + @tableName + ']' +
        'SET ' +
        '   [' + @columnName + '] = ''' + CONVERT(NVARCHAR(255), @refNewValue) + '''' +
        'WHERE [' + @columnName + '] = ''' + CONVERT(NVARCHAR(255), @refValue) + '''';

    -- Prevent some error (Duplicate record) that occurs when replace data in mapping table.
    BEGIN TRY
        exec sp_executesql @sql;
    END TRY
    BEGIN CATCH
    END CATCH
END
CLOSE RelatedTableCursor
DEALLOCATE RelatedTableCursor

最后,我安全地删除了这些数据,没有关于FOREIGN KEY约束的错误。

SET @sql = 'DELETE FROM [' + @refTableName + '] WHERE ' + @refColName + ' = ''' + CONVERT(NVARCHAR(255), @refValue) + '''';
EXEC sp_executesql @sql;

对于源代码,请转到以下链接。

https://gist.github.com/Soul-Master/b8ce875bda51ec515b48