为 SQL 中的所有可为空的列设置 NULL
Setting NULL for all nullable columns in SQL
我遇到以下问题:早期版本的数据库使用值“”而不是 NULL。如果列可以为空,我现在必须将这些值在它们存在的任何地方转换为 NULL。
我试过以下代码:
BEGIN TRAN
DECLARE
@curcolumn VARCHAR(MAX),
@curtable VARCHAR(MAX);
DECLARE cursor_setnull CURSOR
FOR SELECT INFORMATION_SCHEMA.TABLES.TABLE_NAME, INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLES
JOIN INFORMATION_SCHEMA.COLUMNS ON INFORMATION_SCHEMA.TABLES.TABLE_NAME = INFORMATION_SCHEMA.COLUMNS.TABLE_NAME
WHERE INFORMATION_SCHEMA.COLUMNS.IS_NULLABLE = 'YES'
OPEN cursor_setnull
FETCH NEXT FROM cursor_setnull INTO
@curcolumn,
@curtable;
WHILE @@FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM cursor_setnull INTO
@curcolumn,
@curtable;
DECLARE @numrows INT;
DECLARE @query NVARCHAR(MAX);
set @query = 'UPDATE '+@curtable+' SET '+@curcolumn+' = NULL WHERE '+@curcolumn+' = '''''
EXEC sp_executesql @query
END;
CLOSE cursor_setnull;
DEALLOCATE cursor_setnull;
ROLLBACK
在 运行,它为每一列提供以下错误:“无效的对象名称 'column_name'。
如果有人能帮我找出错误,我将不胜感激。
如果您查看生成的查询,您会发现查询不正确。
您需要更改将值提取到游标中的顺序。
FETCH NEXT FROM cursor_setnull INTO
@curcolumn,
@curtable;
应该是
FETCH NEXT FROM cursor_setnull INTO
@curtable,
@curcolumn;
而不是使用 CURSOR
,我会使用一些显式事务批量处理所有事务。我假设 SQL Server 2017+,由于当我问你使用的是什么版本时缺少回复:
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
DECLARE @Delimiter nvarchar(10) = N',' + @CRLF + N' '
SET @SQL = STUFF((SELECT @CRLF + N'BEGIN TRANSACTION;' + @CRLF +
N' UPDATE ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + @CRLF +
N' SET ' + (SELECT STRING_AGG(QUOTENAME(c.[name]) + N' = CASE ' + QUOTENAME(c.[name]) + N' WHEN '''' THEN NULL ELSE '+ QUOTENAME(c.[name]) + N' END',@Delimiter) WITHIN GROUP (ORDER BY c.column_id)
FROM sys.columns c
JOIN sys.types ct ON c.system_type_id = ct.system_type_id
WHERE c.object_id = t.object_id
AND ct.[name] IN ('varchar','nvarchar','char','nchar')
AND c.is_nullable = 1
AND c.is_computed = 0) + N';' + @CRLF +
N'COMMIT TRANSACTION'
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.SCHEMA_ID
WHERE EXISTS (SELECT 1
FROM sys.columns c
JOIN sys.types ct ON c.system_type_id = ct.system_type_id
WHERE c.object_id = t.object_id
AND ct.[name] IN ('varchar','nvarchar','char','nchar')
AND c.is_nullable = 1
AND c.is_computed = 0)
ORDER BY s.schema_id, t.object_id
FOR XML PATH(N''),TYPE).value('(./text())[1]','nvarchar(MAX)'),1,2,N'');
PRINT @SQL; --Your best friend
--EXEC sys.sp_executesql @SQL; --Uncomment to run dynamic statement.
我遇到以下问题:早期版本的数据库使用值“”而不是 NULL。如果列可以为空,我现在必须将这些值在它们存在的任何地方转换为 NULL。
我试过以下代码:
BEGIN TRAN
DECLARE
@curcolumn VARCHAR(MAX),
@curtable VARCHAR(MAX);
DECLARE cursor_setnull CURSOR
FOR SELECT INFORMATION_SCHEMA.TABLES.TABLE_NAME, INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLES
JOIN INFORMATION_SCHEMA.COLUMNS ON INFORMATION_SCHEMA.TABLES.TABLE_NAME = INFORMATION_SCHEMA.COLUMNS.TABLE_NAME
WHERE INFORMATION_SCHEMA.COLUMNS.IS_NULLABLE = 'YES'
OPEN cursor_setnull
FETCH NEXT FROM cursor_setnull INTO
@curcolumn,
@curtable;
WHILE @@FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM cursor_setnull INTO
@curcolumn,
@curtable;
DECLARE @numrows INT;
DECLARE @query NVARCHAR(MAX);
set @query = 'UPDATE '+@curtable+' SET '+@curcolumn+' = NULL WHERE '+@curcolumn+' = '''''
EXEC sp_executesql @query
END;
CLOSE cursor_setnull;
DEALLOCATE cursor_setnull;
ROLLBACK
在 运行,它为每一列提供以下错误:“无效的对象名称 'column_name'。
如果有人能帮我找出错误,我将不胜感激。
如果您查看生成的查询,您会发现查询不正确。
您需要更改将值提取到游标中的顺序。
FETCH NEXT FROM cursor_setnull INTO
@curcolumn,
@curtable;
应该是
FETCH NEXT FROM cursor_setnull INTO
@curtable,
@curcolumn;
而不是使用 CURSOR
,我会使用一些显式事务批量处理所有事务。我假设 SQL Server 2017+,由于当我问你使用的是什么版本时缺少回复:
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
DECLARE @Delimiter nvarchar(10) = N',' + @CRLF + N' '
SET @SQL = STUFF((SELECT @CRLF + N'BEGIN TRANSACTION;' + @CRLF +
N' UPDATE ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + @CRLF +
N' SET ' + (SELECT STRING_AGG(QUOTENAME(c.[name]) + N' = CASE ' + QUOTENAME(c.[name]) + N' WHEN '''' THEN NULL ELSE '+ QUOTENAME(c.[name]) + N' END',@Delimiter) WITHIN GROUP (ORDER BY c.column_id)
FROM sys.columns c
JOIN sys.types ct ON c.system_type_id = ct.system_type_id
WHERE c.object_id = t.object_id
AND ct.[name] IN ('varchar','nvarchar','char','nchar')
AND c.is_nullable = 1
AND c.is_computed = 0) + N';' + @CRLF +
N'COMMIT TRANSACTION'
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.SCHEMA_ID
WHERE EXISTS (SELECT 1
FROM sys.columns c
JOIN sys.types ct ON c.system_type_id = ct.system_type_id
WHERE c.object_id = t.object_id
AND ct.[name] IN ('varchar','nvarchar','char','nchar')
AND c.is_nullable = 1
AND c.is_computed = 0)
ORDER BY s.schema_id, t.object_id
FOR XML PATH(N''),TYPE).value('(./text())[1]','nvarchar(MAX)'),1,2,N'');
PRINT @SQL; --Your best friend
--EXEC sys.sp_executesql @SQL; --Uncomment to run dynamic statement.