将所有 ntext 列转换为 nvarchar(max)

Fed*_*ust 1 stored-procedures sql-server-2008-r2 cursors alter-table

我正在尝试创建一个存储过程来将ntext我的数据库中的所有列转换为nvarchar(max).

这是代码

ALTER PROCEDURE [dbo].[usp_SL_ConvertNtextToNvarchar]
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @table_name nvarchar(128)
  DECLARE @column_name nvarchar(128)
  DECLARE @totalCount int
  DECLARE @count int

  SET @totalCount = 0;
  SET @count = 0;

  -- Eventlogic
  DECLARE tables_cursor CURSOR FOR 

    SELECT so.name as table_name, sc.name as column_name
      FROM sys.objects so
      JOIN sys.columns sc ON so.object_id = sc.object_id
      JOIN sys.types stp ON sc.user_type_id = stp.user_type_id
                        AND stp.name = 'ntext'
     WHERE so.type = 'U' -- to show only user tables
  OPEN tables_cursor

  FETCH NEXT FROM tables_cursor INTO @table_name, @column_name
  WHILE @@FETCH_STATUS = 0
  BEGIN
    EXEC ('ALTER TABLE Eventlogic.dbo.' + @table_name + ' ALTER COLUMN ' + @column_name + ' nvarchar(max);')
    EXEC ('UPDATE Eventlogic.dbo.' + @table_name + ' SET ' + @column_name + '=' + @column_name + ' ')
    SET @count = @count + 1;
    IF @count > 0
      PRINT ('Eventlogic.dbo.' + @table_name + '.' + @column_name + ' ' + CAST(@count AS nvarchar(10)))
    SET @totalCount = @totalCount  + @count;
    FETCH NEXT FROM tables_cursor INTO @table_name, @column_name
  END 
  CLOSE tables_cursor
  DEALLOCATE tables_cursor
  PRINT ('Total columns updated: ' + CAST(@totalCount AS nvarchar(10)))  

END;
Run Code Online (Sandbox Code Playgroud)

每当我尝试运行它时,都会收到此错误:

消息 16924,级别 16,状态 1,过程 usp_SL_ConvertNtextToNvarchar,第 37 行
Cursorfetch:INTO 列表中声明的变量数量必须与所选列的数量匹配。

我们在不同的表中有 338 列 ntext由于遗留问题,。

我们升级到 SQL Server 2008 R2,因此我们想将这些列转换为 nvarchar(max).

我们希望遵循ntext vs nvarchar(max)中的建议,其中 Conwell 建议在更改后进行更新。

SQL Server 将文本从 LOB 结构移动到表中(如果小于 8,000 字节)。因此,当我们再次使用 IO STATISTICS 运行选择时,我们会得到 0 个 LOB 读取。

任何有关此错误的帮助都会很棒。

更新

更新了 Martin 提到的代码。在给出错误之前,它实际上只是改变了列表中的第一个。

第二次更新

在对代码进行更改以修复第二次提取后,我关闭了 SQL Management Studio。再次打开 SQL Management Studio 并运行它,它工作正常。所以再次感谢马丁。

提前致谢。

费德里科

Aar*_*and 5

如果您在阅读我的答案之前解决了这个问题,那么它不太可能对您的特定情况有用(除非您需要在多个数据库中执行此操作),但对于此类工作,我更喜欢字符串连接而不是游标。主要是因为您可以打印字符串而不是执行它,验证至少前 8K 值看起来正确无误。

DECLARE @sql NVARCHAR(MAX) = N'USE Eventlogic;';

SELECT @sql += N'
  ALTER TABLE ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name)
  + ' ALTER COLUMN ' + QUOTENAME(c.name) 
  + CASE WHEN c.system_type_id = 99 THEN ' N' ELSE ' ' END
  + 'VARCHAR(MAX)' + CASE WHEN c.is_nullable = 0 THEN ' NOT NULL' ELSE '' END 
  + ';
  UPDATE ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) 
    + ' SET ' + QUOTENAME(c.name) + ' = ' + QUOTENAME(c.name) + ';
  PRINT ''' + QUOTENAME(s.name) + '.' + QUOTENAME(REPLACE(t.name,'''','''''')) 
    + '.' + QUOTENAME(c.name) + ' (' 
    + CONVERT(VARCHAR(12), COUNT(*) OVER(PARTITION BY c.[object_id])) 
    + ' columns)'';'
FROM sys.columns AS c
INNER JOIN sys.tables AS t
  ON c.[object_id] = t.[object_id]
INNER JOIN sys.schemas AS s
  ON t.[schema_id] = s.[schema_id]
  WHERE c.system_type_id IN (35,99);

SET @sql += N'
PRINT ''Total columns updated: ' + CONVERT(VARCHAR(12), @@ROWCOUNT) + ''';';

PRINT @sql;
--EXEC sp_executesql @sql;
Run Code Online (Sandbox Code Playgroud)

当您对PRINT输出感到满意时,取消注释EXEC并再次运行它。

Jon Seigel 的脚本提供了额外的功能(处理参与 FULLTEXT 索引的列)。