sqlserver批量修改null及空字符串

在做数据迁移的过程中总会出现各种始料不及的问题,原始库中的数据总会多出不少的冗余数据或无效数据,最近工作需要需要将sqlserver数据库中的所有表存在的空字符串以及null替换为"NaN",今天来研究一下sqlserver中的空字符串以及null

null 和空字符串"的区别

null不指向任何对象,没有任何值,而空字符串"代表一个长度为0的字符串

假如有个字段是money,null可以理解为 “我有没有钱关你啥事儿 ”,而 空字符"表示“我真的没有钱,我就是个穷B”,那么数据存储中空值到底用NULL还是空字符,这个争议比较多,根据个人需要吧,区别不大。个人习惯用null值,毕竟sqlserver中有isnull()函数是可以方便的检索null值,这个对于业务上的一些处理比较方便,另外是isnull()函数是不能识别空字符的,这也与我们为什么要写下面的sql脚本。

如何来解决整个数据库的替换

整个替换逻辑大致就是循环数据库表,然后循环表中所有字段,将所有的字段检索替换一遍。逻辑简单,主要是语法上的书写。

需要用到的SQL语句

-- 查询表中所有字段名
select name from syscolumns where id=object_id('TEST01')
-- 查询数据库所有表名
select table_name from information_schema.tables

单表修改

declare @colname  varchar(100),
        @sql      varchar(8000),
		@count int,
		@num int				
SET @sql=''
SET @num=1
select @count=count(*) from syscolumns where id=object_id('TEST01')
while @num <= @count 
BEGIN
	select  @colname=name from syscolumns s where id=object_id('TEST01') and colid = @num
    set @sql='update TEST01 set '+@colname+'=''NaN'''+'where '+@colname+'='''' or '+@colname+' is NULL'
	exec (@sql)
	set @num=@num +1 
end ;

这个比较简单 ,查询出表中字段数量,然后查询表中所有字段名,根据数量来循环更新语句。需要注意的是拼接sql语句不要漏掉引号。稍微修改一下,做个存储过程,如下:

单表存储过程

create procedure test_table_update
@tablename varchar(100)
as
declare @colname  varchar(100),
        @sql      varchar(8000),
		@count int,
		@num int				
SET @sql=''
SET @num=1
select @count=count(*) from syscolumns where id=object_id(@tablename)
while @num <= @count 
BEGIN
	select  @colname=name from syscolumns s where id=object_id(@tablename) and colid = @num
    set @sql='update '+@tablename+' set '+@colname+'=''NaN'''+'where '+@colname+'='''' or '+@colname+' is NULL'
	exec (@sql)
	set @num=@num +1 
end ;

数据库修改

use 数据库名;
declare @tableName  varchar(100),  -- 表名
		@tableCount  varchar(100), -- 表数量
		@colname  varchar(100),    -- 字段名
		@sql      varchar(8000),  -- 执行sql
		@count int,  -- 字段数量
		@num int,   -- 字段数量初始
		@tableNum int -- 表数量初始
SET @tableNum=1
select @tableCount=count(*) from information_schema.tables  -- 将@tableCount赋值为表数量
while @tableNum <= @tableCount -- 循环表
BEGIN
	select @tableName=table_name from (select row_number() over ( order by table_name) as row ,* from information_schema.tables) t  where t.row =@tableNum  -- 给查询到的表名赋予序号并按序号查询
	select @count=count(*) from syscolumns where id=object_id(@tableName) 
				SET @num=1
				while @num <= @count  -- 循环字段
						 BEGIN
								select  @colname=name from syscolumns s where id=object_id(@tableName) and colid = @num  -- 查询字段名
								set @sql='update '+@tableName+' set '+@colname+'=''NaN'''+'where '+@colname+'='''' or '+@colname+' is NULL'  --更新
								exec (@sql)  --执行
								set @num=@num +1  -- 下一个字段
						end ;
	set @tableNum=@tableNum +1  -- 下一张表
end ;

尝试用存储过程来实现数据库下所有表修改,但不同数据库不能相互操作走了弯路, 所以只能用上述的 use database;
虽然无效,但是存储过程中拼接赋值sql带参数的写法是可以保留以供学习,有兴趣可以看看。

ALTER procedure test_schema_update02
@schemaName varchar(100) -- 数据库名
as
declare @tableName  varchar(100),  -- 表名
		@tableCount  varchar(100), -- 表数量
		@colname  varchar(100),    -- 字段名
        @sql      varchar(8000),  -- 执行sql
		@count int,  -- 字段数量
		@num int,   -- 字段数量初始
		@tableNum int, -- 表数量初始
		@schemaSql nvarchar(1000), -- 数据库拼接sql	
		@schemaSql02 nvarchar(1000)							
SET @tableNum=1
set @schemaSql= 'select @cnt=count(*) from '+@schemaName+'.information_schema.tables'
EXECUTE sp_executesql @schemaSql, N'@schemaName varchar(100),@cnt int OUTPUT', @schemaName = @schemaName, @cnt=@tableCount OUTPUT

while @tableNum <= @tableCount -- 循环表
BEGIN
set @schemaSql02 = 'select @cnt=table_name from (select row_number() over ( order by table_name) as row ,* from  '+@schemaName+'.information_schema.tables) t  where t.row =@tableNum' 
EXECUTE sp_executesql @schemaSql02, N'@schemaName varchar(100) ,@tableNum varchar(100) ,@cnt varchar(100) OUTPUT', @schemaName = @schemaName,@tableNum=@tableNum,@cnt=@tableName OUTPUT

-- select @tableName=table_name from (select row_number() over ( order by table_name) as row ,* from information_schema.tables) t  where t.row =@tableNum  -- 给查询到的表名赋予序号并按序号查询
	select @count=count(*) from syscolumns where id=object_id(@tableName) 
				SET @num=1
				while @num <= @count  -- 循环字段
						 BEGIN
								select  @colname=name from syscolumns s where id=object_id(@tableName) and colid = @num  -- 查询字段名
								set @sql='update '+@tableName+' set '+@colname+'=''NN'''+'where '+@colname+'='''' or '+@colname+' is NULL'  --更新
								exec (@sql)  --执行
								set @num=@num +1  -- 下一个字段
						end ;
	set @tableNum=@tableNum +1  -- 下一张表
 end ;