【问题标题】:Sql-server – Convert all ntext columns to nvarchar(max)Sql-server – 将所有 ntext 列转换为 nvarchar(max)
【发布时间】:2022-01-19 16:42:27
【问题描述】:

我正在尝试将数据库中的所有 ntext 列转换为 nvarchar(max)。

这是代码:

        DECLARE @command NVARCHAR(MAX);
        DECLARE @numberOfRecordsToUpdate as int;
        DECLARE @numberOfRowsUpdated as int;
        DECLARE @totalNumberOfRecordsToUpdate as int;
        DECLARE @object_id INT,
                @column_id INT,
                @SchemaName varchar(250),
                @tableName varchar(250),
                @columnName SYSNAME,
                @isNullable BIT,
                @System_Type_Id INT,
                @lenght INT

        CREATE TABLE #chunkOfObjects(ID int, column_id INT, tableName varchar(250), columnName          SYSNAME, isNullable BIT);

        CREATE TABLE #objectsToUpdate(
                ID int,
                column_id INT,
                SchemaName varchar(250),
                tableName varchar(250),
                columnName SYSNAME,
                isNullable BIT,
                System_Type_Id INT,
                lenght INT);

        INSERT INTO #objectsToUpdate 
                        SELECT c.object_id, column_id, (s.name), (o.name), c.name, c.is_nullable, c.system_type_id, DATALENGTH(c.name) as lenght
                        FROM sys.all_columns AS c
                        INNER JOIN sys.objects AS o ON c.object_id = o.object_id
                        INNER JOIN sys.schemas as s ON s.schema_id = o.schema_id
                        WHERE o.type = 'U' AND  c.system_type_id in ('99','35','34') order by (o.name) ;

        DECLARE col_cursor CURSOR FAST_FORWARD FOR SELECT * FROM #objectsToUpdate;
        OPEN col_cursor;
        FETCH NEXT FROM col_cursor INTO @object_id, @column_id, @SchemaName, @tableName, @columnName, @isNullable, @System_Type_Id, @lenght;
        WHILE @@FETCH_STATUS = 0
        BEGIN

                    SELECT @numberOfRecordsToUpdate = count(ID) FROM #objectsToUpdate;
                    SELECT @totalNumberOfRecordsToUpdate = @numberOfRecordsToUpdate;
                    PRINT CURRENT_TIMESTAMP;
                    PRINT 'Cleaning';
                    WHILE (@numberOfRecordsToUpdate > 0)
                        BEGIN
                            INSERT INTO #chunkOfObjects (ID, column_id, tableName, columnName, isNullable  ) SELECT top(10) ID, column_id, tableName, columnName, isNullable FROM #objectsToUpdate;
                            DELETE FROM #objectsToUpdate WHERE ID in ( SELECT ID FROM #chunkOfObjects );
                            BEGIN TRANSACTION tr;                       
                                SELECT @command =
                                    'ALTER TABLE '
                                    + QUOTENAME(OBJECT_SCHEMA_NAME( (SELECT ID FROM #chunkOfObjects)) )
                                    + '.' + QUOTENAME(OBJECT_NAME( (SELECT ID FROM #chunkOfObjects)) )
                                    + ' ALTER COLUMN '
                                    + QUOTENAME((SELECT @columnName FROM #chunkOfObjects where))
                                    +' varchar(max)'    
                                    + CASE
                                        WHEN ( SELECT @isNullable FROM #chunkOfObjects ) = 1 THEN '' ELSE 'NOT'
                                      END
                                    + ' NULL;';
                                PRINT @command;
                                SELECT @command ='UPDATE ' +QUOTENAME(OBJECT_SCHEMA_NAME( (SELECT ID  FROM #chunkOfObjects )) ) + '.' 
                                    + QUOTENAME(OBJECT_NAME( (SELECT ID FROM #chunkOfObjects )) ) + ' SET ' 
                                    + QUOTENAME((SELECT @columnName FROM #chunkOfObjects )) + ' = '
                                    + QUOTENAME((SELECT @columnName FROM #chunkOfObjects )) 
                                PRINT @command;
                                EXEC sp_executesql @command
                                SELECT @numberOfRowsUpdated = COUNT(ID) FROM #chunkOfObjects;
                                PRINT 'Updtated: ' + CAST(@numberOfRowsUpdated as varchar(15)) + ' row(s) of ' + CAST(@totalNumberOfRecordsToUpdate as varchar(15));
                                TRUNCATE TABLE #chunkOfObjects;
                            COMMIT TRANSACTION tr;                  
                            SELECT @numberOfRecordsToUpdate = count(ID) FROM #objectsToUpdate;
                            PRINT 'Remaining ' + CAST(@numberOfRecordsToUpdate as varchar(15)) + ' row(s) ' + NCHAR(10) + '-------------';
                        END
                    PRINT CURRENT_TIMESTAMP
            FETCH NEXT FROM col_cursor INTO @object_id, @column_id, @SchemaName, @tableName, @columnName, @isNullable, @System_Type_Id, @lenght;
        END
        CLOSE col_cursor;
        DEALLOCATE col_cursor;
        DROP TABLE #objectsToUpdate;
        DROP TABLE #chunkOfObjects;

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

Msg 512, Level 16, State 1, Line 60
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

子查询是当我试图选择卡盘对象来改变或更新表时:

SELECT ID FROM #chunkOfObjects

如果我使用下面的:

SELECT ID FROM #chunkOfObjects where column_id =@column_id  

它只需要一个 ID,而不是在 #chunkOfObjects 表上循环

任何解决此错误的帮助都会很棒。

【问题讨论】:

  • 这将是像 QUOTENAME(OBJECT_SCHEMA_NAME( (SELECT ID FROM #chunkOfObjects)) ) 这样的行,因为您在 #chunkOfObjects 中似乎有超过 1 行。
  • @Larnu 正是我的问题。如果有人可以帮助解决它。我的意思是如何通过代码修改以从我的#chunckobject中一一选择ID
  • 您需要添加一个WHERE。大概在object_id上。
  • 旁注,您正在将所有ntextimagetext 列更改为varchar(MAX)。这可能会导致大量数据丢失。您应该分别使用nvarcharvarbinaryvarchar 数据类型。
  • 感谢您的注意,我将更改我的代码

标签: sql-server for-loop chunks nvarchar ntext


【解决方案1】:

以上看起来您使问题过于复杂。您应该能够通过一些简单的字符串聚合更轻松地实现这一点。我假设您使用的是 SQL Server 2017+;如果不使用“旧”FOR XML PATH 方法:

DECLARE @SQL nvarchar(MAX),
        @CRLF nchar(2) = NCHAR(13) + NCHAR(10);

SELECT @SQL = STRING_AGG(N'ALTER TABLE ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + N' ALTER COLUMN ' + QUOTENAME(c.[name]) + N' ' + 
                         CASE ct.[name] WHEN N'text' THEN N'varchar'
                                        WHEN N'ntext' THEN N'nvarchar'
                                        WHEN N'image' THEN N'varbinary'
                         END + N'(MAX) ' +
                         CASE c.is_nullable WHEN 1 THEN N'NULL'
                                            ELSE N'NOT NULL'
                         END + N';',@CRLF)
FROM sys.schemas s
     JOIN sys.tables t ON s.schema_id = t.schema_id
     JOIN sys.columns c ON t.object_id = c.object_id
     JOIN sys.types ct ON c.user_type_id = ct.user_type_id
WHERE ct.[name] IN (N'text',N'ntext',N'image');

PRINT @SQL;
EXEC sys.sp_executesql @SQL;

【讨论】:

  • 感谢您的帮助。现在我看到没有更新列,我必须在转换后更新列。并且没有块表。我有大表,所以我必须使用块表。
  • 什么是“块表”?
  • 选择一些记录从原始表更新到临时表,就像我所做的那样:SELECT top(10) ID, column_id, tableName, columnName, isNullable FROM #objectsToUpdate;
  • “我将列更新为自身” 为什么是 @satcha ?除了浪费时间之外,这毫无意义。请参阅我之前的comment。恕我直言,我认为没有理由在我的解决方案中添加冗余和性能不佳的代码。
  • @satcha 如果它们超过 8k,你肯定不应该关心,因为超过 8k 的 nvarchar(max) 也存储在行外,所以根本不会有任何变化.我建议在“没有必要”的情况下写下该注释
猜你喜欢
  • 1970-01-01
  • 2010-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-09
  • 2015-08-06
  • 1970-01-01
相关资源
最近更新 更多