1

我正在尝试将数据库中的所有 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 表上循环

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

4

1 回答 1

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;
于 2021-12-16T15:53:46.397 回答