当前正在做一个项目,我必须更新85个表上的数据,将当前的空字符串替换为NULL值。 这是一个简单的SQL查询,但是由于它是一个敏感的环境,因此如果出现任何问题,我们需要恢复该状态。
主要思想是创建一个表来保存要回滚的数据。但我试图避免创建85个表。
我将举一个较小的示例:
有4张桌子
------------------------------------
| airplane |
------------------------------------
| air_ID | color | tail_number |
------------------------------------
| 1 | red | |
| 2 | green | |
| 3 | black | 21AF |
------------------------------------
------------------------------------
| bus |
------------------------------------
| bus_ID | color | tag_number |
------------------------------------
| 1 | red | AAY-464 |
| 2 | green | |
| 3 | black | |
------------------------------------
------------------------------------
| train |
------------------------------------
| tr_ID | color | designated_name |
------------------------------------
| 1 | red | 99212 |
| 2 | green | |
| 3 | black | |
------------------------------------
------------------------------------
| Cruise_Ship |
------------------------------------
| sea_ID | color | hull_number |
------------------------------------
| 1 | red | |
| 2 | green | MAGDA |
| 3 | black | |
------------------------------------
所以我用数据创建了一个临时表
-------------------------------------------------
| update_table |
-------------------------------------------------
| table_name | ID_colname | ID | col_name |
-------------------------------------------------
| airplane | air_ID | 1 | tail_number |
| airplane | air_ID | 2 | tail_number |
| bus | bus_ID | 2 | tag_number |
| bus | bus_ID | 3 | tag_number |
| train | tr_ID | 2 |designated_name|
| train | tr_ID | 3 |designated_name|
|Cruise_Ship | sea_ID | 1 | hull_number |
|Cruise_Ship | sea_ID | 3 | hull_number |
-------------------------------------------------
使用此表,我试图生成一个动态SQL以一次调用更新所有表
SET @SQLString = N'UPDATE @table
SET @value = '+ @empty +'
where @key = @id';
SET @ParmDefinition = N'@table nvarchar(max),
@value nvarchar(max) ,
@key nvarchar(max) ,
@id int';
DECLARE @table nvarchar(255)
DECLARE @value nvarchar(255)
DECLARE @key nvarchar(255)
DECLARE @id int
select @table = table_name, @id = ID, @key = ID_colname , @value = col_name from update_table
EXECUTE sp_executesql
@SQLString
,@ParmDefinition
,@table
,@value
,@key
,@id
;
但这不起作用,任何人都对如何改进此查询有一个想法?
这是一个引人注目的环境,开发人员不是执行代码的人,因此它需要客户证明。 该代码会隔夜运行,以免打扰白天的工作。
答案 0 :(得分:3)
如果SELECT语句返回多行,并且该变量引用一个非标量表达式,则该变量将设置为结果集最后一行中该表达式返回的值。
这意味着只为变量分配了最后一行的值。 因此,只有[Cruise_Ship]。[hull_number]将传递给sp_executesql,并且这是用脚本更新的唯一列。
要存储多个值,应使用表变量。
sp_executesql确实接受参数,并且用于构建动态查询。
但是,我认为您不能将表值变量作为参数传递。
已添加:检查this,了解如何将表值变量传递给sp_executesql。
这是您的代码出错的地方。
select @table = table_name, @id = ID, @key = ID_colname , @value = col_name from update_table
我知道这不太好,但是以下代码可以完成这项工作。 而且我建议无论您是否进行备份,都将其包装在TRANSACTION中。
DECLARE @empty NVARCHAR(10)
SET @empty = 'NULL'
SELECT
'UPDATE ' + s.name + '.' + t.name + '
SET [' + c.name + '] = ' + @empty + '
WHERE LTRIM([' + c.name + ']) = ''''
END;'
FROM sys.tables t
INNER JOIN sys.schemas s
ON t.schema_id = s.schema_id
INNER JOIN sys.columns c
ON t.object_id = c.object_id
ORDER BY
s.name
,t.name
,c.column_id
答案 1 :(得分:0)
我同意亚当·亚姆(Adam Yam)的观点,我只是扩大了答案,以包括来自update_tables的所需数据。
这样,仅对表上的这8个条目执行SQL。
结果是示例中正确更新了4个表。
DECLARE @currentId INT
SELECT @currentId = MIN(tabl.ID) from udpate_table tabl
DECLARE @sql NVARCHAR(MAX)
WHILE (1 = 1)
BEGIN
--- execute for the current pk
BEGIN
SELECT @sql =
'UPDATE ' + s.name + '.' + t.name + '
SET [' + c.name + '] = ''''
where ' + s.name + '.' + t.name + '.' + tab.ID_colname + ' = ' + convert (varchar(20), tab.ID) + ' '
FROM sys.tables t
INNER JOIN sys.schemas s
ON t.schema_id = s.schema_id
INNER JOIN sys.columns c
ON t.object_id = c.object_id
JOIN update_table tab
on t.name = tab.table_name
and c.name = tab.col_name
and tab.ID = @currentId
ORDER BY
tab.ID
,s.name
,t.name
,c.column_id
END
exec sp_executesql @sql
-- select the next id to handle
SELECT TOP 1 @currentId = tabl.ID
FROM update_table tabl
WHERE tabl.ID > @currentId
ORDER BY tabl.ID
IF @@ROWCOUNT = 0 BREAK;
END