データベース内のすべての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;
_
実行しようとすると、次のエラーが発生します。
メッセージ16924、レベル16、状態1、プロシージャusp_SL_ConvertNtextToNvarchar、行37
Cursorfetch:INTOリストで宣言された変数の数は、選択された列の数と一致する必要があります。
レガシーのため、異なるテーブル全体にntext
として338列があります。
SQL Server 2008 R2にアップグレードしたため、これらの列をnvarchar(max)
に変換します。
ここでアドバイスに従いたい ntext vs nvarchar(max) ここで、Conwellは変更後に更新を行うことを提案しています。
SQLサーバーは、テキストをLOB構造からテーブルに移動します(8,000バイト未満の場合)。したがって、IO STATISTICSを使用して選択を再度実行すると、LOB読み取りは0になります。
このエラーの助けがあればすばらしいでしょう。
[〜#〜]更新[〜#〜]
マーティンが述べたようにコードを更新しました。実際には、エラーが発生する前にリストの最初の1つだけが変更されています。
2回目の更新
2番目のフェッチを修正するためにコードを変更した後、SQL Management Studioを閉じました。 SQL Management Studioを再度開いて実行すると、問題なく動作しました。マーティンに再度感謝します。
前もって感謝します。
フェデリコ
OK、SPをQUOTENAME
と@MartinSmithのようなschema
を使用して書き換えました。 SPを使用しています。これは、SPラッパーを使用しないスタンドアロンコードのように見えるので、このようなものにはより意味があります。
名前の奇数文字を処理するには、QUOTENAME
を使用します。たとえば、Table-Test
は有効なテーブル名ですが、[]
sをその周囲に[Table-Test]
を付けない限り、コードでは機能しません。 QUOTENAME
がそれを処理します。また、名前に ']が含まれている場合も処理します。 schemas
を含め、必要に応じてQUOTENAME
を使用する動的SQLを実行する場合は、一般的にベストプラクティスと見なされています。
USE [EventLogic]
GO
/****** Object: StoredProcedure [dbo].[usp_SL_ConvertNtextToNvarchar] Script Date: 08/08/2013 16:28:58 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_SL_ConvertNtextToNvarchar]
AS
/*
*/
BEGIN
SET NOCOUNT ON;
DECLARE @sql nvarchar(max)
DECLARE @table_schema nvarchar(128)
DECLARE @table_name nvarchar(128)
DECLARE @column_name nvarchar(128)
DECLARE @totalCount int
DECLARE @count int
SET @totalCount = 0;
SET @count = 0;
SET @sql = '';
-- Eventlogic
DECLARE tables_cursor CURSOR FOR
SELECT SCHEMA_NAME(so.schema_id) AS table_schema, 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_schema, @table_name, @column_name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = 'ALTER TABLE Eventlogic.'+QUOTENAME(@table_schema)+'.' +
QUOTENAME(@table_name) + ' ALTER COLUMN ' +
QUOTENAME(@column_name) + ' nvarchar(max);'
EXEC sp_executesql @sql
--PRINT @sql
SET @sql = 'UPDATE Eventlogic.'+QUOTENAME(@table_schema)+'.' +
QUOTENAME(@table_name) + ' SET ' +
QUOTENAME(@column_name) + '=' +
QUOTENAME(@column_name) + ' '
EXEC sp_executesql @sql
--PRINT @sql
SET @count = @count + 1;
IF @count > 0
PRINT ('Eventlogic.'+@table_schema+'.' + @table_name + '.' + @column_name + ' ' + CAST(@count AS nvarchar(10)))
SET @totalCount = @totalCount + @count;
FETCH NEXT FROM tables_cursor INTO @table_schema, @table_name, @column_name
END
CLOSE tables_cursor
DEALLOCATE tables_cursor
PRINT ('Total columns updated: ' + CAST(@totalCount AS nvarchar(10)))
END;
GO
私の回答を読む前にこれを並べ替えて、特定のケースでは役に立たないようにする場合(複数のデータベースでこれを行う必要がない限り)、このタイプの作業では、カーソルよりも文字列連結を優先します。主に、文字列を実行する代わりに出力できるため、少なくとも最初の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;
PRINT
の出力に満足したら、EXEC
のコメントを外して、もう一度実行します。
Jon Seigelのスクリプト は、追加の機能を提供します(FULLTEXTインデックスに参加する列を扱います)。
以下は、分析のためにステートメントを出力してから実行できる1つのバリエーションです。
DECLARE @CurrentDataType VARCHAR(max)
DECLARE @DataTypeToChange VARCHAR(max)
SET @CurrentDataType = 'datetime' ---CHANGE HERE !!
SET @DataTypeToChange = 'smalldatetime' ---CHANGE HERE !!
SELECT 'alter table ' + OBJECT_SCHEMA_NAME(T.[object_id], DB_ID()) + '.' + T.[name] + CHAR(10) + ' alter column ' + C.[name] + ' ' + @DataTypeToChange + ' ' + CASE
WHEN C.[is_nullable] = 0
THEN 'not null '
ELSE ' null '
END
FROM sys.[tables] AS T
INNER JOIN sys.[all_columns] C ON T.[object_id] = C.[object_id]
INNER JOIN sys.[types] DTY ON C.[system_type_id] = DTY.[system_type_id]
AND C.[user_type_id] = DTY.[user_type_id]
WHERE T.[is_ms_shipped] = 0
AND DTY.NAME = '' + @CurrentDataType + ''
ORDER BY T.[name]
,C.[column_id]