2009-12-10 18 views
31

Recientemente hemos trasladado nuestra base de datos de nuestro servidor SQL Server 2005 a nuestro servidor SQL Server 2008. Todo se movió demasiado bien, sin embargo, ahora estamos descubriendo que estamos obteniendo conflictos de intercalación. El servidor anterior tenía una intercalación diferente con el nuevo servidor.Actualización Colación de todos los campos en la base de datos sobre la marcha

Ahora nuestras tablas creadas antes del movimiento son una intercalación, y las creadas después son otra intercalación.

¿Hay alguna manera de actualizar las tablas/columnas con la antigua intercalación con la nueva intercalación?

Entiendo que el establecimiento de la intercalación de base de datos/servidor predeterminada no modifica ninguna tabla existente (link). Realmente no quiero recrear la base de datos si no es necesario.

Cualquier ayuda realmente apreciada.

ACTUALIZACIÓN

Gracias por su ayuda chicos, finalmente tuvieron que trabajar.

Para futuras referencias, aquí es mi guión final:

SELECT 'ALTER TABLE [' + SYSOBJECTS.Name + '] ALTER COLUMN [' + SYSCOLUMNS.Name + '] ' + 
SYSTYPES.name + 
    CASE systypes.NAME 
    WHEN 'text' THEN ' ' 
    ELSE 
    '(' + RTRIM(CASE SYSCOLUMNS.length 
    WHEN -1 THEN 'MAX' 
    ELSE CONVERT(CHAR,SYSCOLUMNS.length) 
    END) + ') ' 
    END 

    + ' ' + ' COLLATE Latin1_General_CI_AS ' + CASE ISNULLABLE WHEN 0 THEN 'NOT NULL' ELSE 'NULL' END 
    FROM SYSCOLUMNS , SYSOBJECTS , SYSTYPES 
    WHERE SYSCOLUMNS.ID = SYSOBJECTS.ID 
    AND SYSOBJECTS.TYPE = 'U' 
    AND SYSTYPES.Xtype = SYSCOLUMNS.xtype 
    AND SYSCOLUMNS.COLLATION IS NOT NULL 
    AND NOT (sysobjects.NAME LIKE 'sys%') 
    AND NOT (SYSTYPES.name LIKE 'sys%') 
    GO 

Aquí es el site que contenía el guión me basé en. Tuve que modificarlo para que funcione correctamente.

+1

Russell, usted debe hacer su solución de una respuesta! –

+0

Gracias Philipp, de todos modos está en la cima de la pregunta, y los Potros de OMG me ayudaron a llegar allí. :) – Russell

Respuesta

6

Puede cambiar la intercalación de cualquier nuevos objetos que se crean en una base de datos de usuario utilizando la cláusula COLLATE de la declaración ALTER DATABASE. Esta instrucción hace no cambia la intercalación de las columnas en cualquier tabla existente definida por el usuario. Estos se pueden cambiar utilizando la cláusula COLLATE de ALTER TABLE.

Referencia: Setting and Changing the Database Collation

Si hay demasiadas columnas, puede recorrer sys.columns para aplicar la sentencia ALTER TABLE.

+1

Sí, ese no es mi problema, mi problema es con las columnas existentes. – Russell

+0

Por eso la última línea dice que 'ALTER TABLE' –

+0

No es una opción, ya que hay demasiados campos para hacerlo. – Russell

2

Una opción es utilizar un programa como Red Gate SQL Compare (estoy seguro de que hay otros también). Con él puedes generar archivos de script para tu esquema con colación incluida (asegúrate de activarlo en las opciones), luego haz una búsqueda/reemplazo en los archivos actualizándolos a la nueva intercalación, luego vuelve a compararlos con tu real base de datos.

En este punto, SQL Compare podrá aplicar esos cambios (o guardar los cambios en un archivo de script, si lo prefiere), y todas las columnas existentes serán reparadas.

En teoría, usted podría hacer todo esto mientras se encuentre aún en el período de prueba, aunque yo sugeriría que es una buena herramienta para seguir porque facilita muchas tareas SQL.

+0

Redgate Compare es una gran herramienta para usar también. : D – Russell

10

Sólo en caso de cualquiera que busque en esto está utilizando SQL Server 2008, que tenía que hacer un par de modificaciones:

SELECT 'ALTER TABLE [' + sys.objects.name + '] ALTER COLUMN [' 
+ sys.columns.name + '] ' + sys.types.name + 
    CASE sys.types.name 
    WHEN 'text' THEN ' ' 
    ELSE 
    '(' + RTRIM(CASE sys.columns.max_length 
    WHEN -1 THEN 'MAX' 
    ELSE CONVERT(CHAR,sys.columns.max_length) 
    END) + ') ' 
    END 

    + ' ' + ' COLLATE Latin1_General_BIN ' + CASE sys.columns.is_nullable WHEN 0 THEN 'NOT NULL' ELSE 'NULL' END 
    FROM sys.columns , sys.objects , sys.types 
    WHERE sys.columns.object_id = sys.objects.object_id 
    AND sys.objects.TYPE = 'U' 
    AND sys.types.system_type_id = sys.columns.system_type_id 
    AND sys.columns.collation_name IS NOT NULL 
    AND NOT (sys.objects.NAME LIKE 'sys%') 
    AND NOT (sys.types.name LIKE 'sys%') 
+0

Gracias por el consejo. ¿Qué fue cambiado? Utilicé la secuencia de comandos anterior en SQL Server 2008.: D – Russell

+1

Esto usa sys.columns en lugar de SYSCOLUMNS – edosoft

+0

, ¿cómo se recorrerá esto y se ejecutarán las instrucciones? – Chagbert

4

Cómo sobre: ​​

DECLARE @collation NVARCHAR(64) 
SET @collation = 'Latin1_General_CI_AS' 

SELECT 
    'ALTER TABLE [' + TABLE_SCHEMA + '].[' + TABLE_NAME + '] ' 
    + 'ALTER COLUMN [' + COLUMN_NAME + '] ' 
    + DATA_TYPE + '(' + CASE CHARACTER_MAXIMUM_LENGTH 
     WHEN -1 THEN 'MAX' 
     ELSE CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) END + ') ' 
    + 'COLLATE ' + @collation + ' ' 
    + CASE WHEN IS_NULLABLE = 'NO' THEN 'NOT NULL' ELSE 'NULL' END 
FROM INFORMATION_SCHEMA.columns 
WHERE COLLATION_NAME IS NOT NULL 
AND COLLATION_NAME <> @collation 
+1

'AND TABLE_NAME IN (SELECT TABLE_NAME de information_schema.tables WHERE table_type = 'BASE TABLE')' – danihp

3

Para solucionar este problema, es necesario mucha más potencia de fuego que este script proporciona.Intenté el script y encontré problemas con objetos dependientes que no se pudieron actualizar: índices, claves y procedimientos. La solución final tomó solo 5 minutos con esta aplicación de proyecto de código. La aplicación dice que es para SQL Server 2000 pero lo utilizó con éxito con 2008.

http://www.codeproject.com/Articles/12753/SQL-Server-2000-Collation-Changer

No puedo enfatizar esto lo suficiente. RESPALDE SU BASE DE DATOS. Tuve que usar mi copia de seguridad tres veces para completar esta tarea.

-3

El código no puede tener en cuenta los bytes dobles NText, NChar y NVarchar. Si tiene NText, fallará si Ntext (16) no puede establecer el tamaño en NText.

Para NCHAR y NVARCHAR se duplica la longitud, ya que no se divide por 2. tamaño

Otro pequeño detalle peculiar, es que por lo menos Nvarchar, -1 no es MAX, pero es 0.

Este es un truco muy, muy feo en el código, sólo para ilustrar los temas:

ALTER TABLE [BlanketBruger] ALTER COLUMN [BrugerNavn] nvarchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [BlanketBruger] ALTER COLUMN [BrugerFuldNavn] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [blanketgruppe] ALTER COLUMN [GruppeNavn] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [blanketSerie] ALTER COLUMN [SerieTitel] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [blanketSerie] ALTER COLUMN [SerieAlias] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [FormUse] ALTER COLUMN [HostName] nvarchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [BackendLog] ALTER COLUMN [value1] nvarchar(1000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [BackendLog] ALTER COLUMN [value2] nvarchar(1000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [BackendLog] ALTER COLUMN [ip] varchar(20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [BackendLog] ALTER COLUMN [username] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [BackendLog] ALTER COLUMN [gruppenavn] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [BackendLog] ALTER COLUMN [scriptname] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [BackendLog] ALTER COLUMN [querystring] nvarchar(1000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [BackendLog] ALTER COLUMN [useragent] nvarchar(400) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [BackendLog] ALTER COLUMN [sessionid] varchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [BackendLog] ALTER COLUMN [htmlcontent] nvarchar(MAX) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [frontendlog] ALTER COLUMN [value1] nvarchar(1000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [frontendlog] ALTER COLUMN [value2] nvarchar(1000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [frontendlog] ALTER COLUMN [ip] nvarchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [frontendlog] ALTER COLUMN [querystring] nvarchar(1000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [frontendlog] ALTER COLUMN [useragent] nvarchar(400) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [frontendlog] ALTER COLUMN [sessionid] nvarchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [log4net] ALTER COLUMN [Thread] varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [log4net] ALTER COLUMN [Level] varchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [log4net] ALTER COLUMN [Logger] varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [log4net] ALTER COLUMN [Message] text COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [log4net] ALTER COLUMN [Exception] varchar(MAX) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [log4net] ALTER COLUMN [Server] varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [OioSamlLog] ALTER COLUMN [Server] varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [OioSamlLog] ALTER COLUMN [Thread] varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [OioSamlLog] ALTER COLUMN [Level] varchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [OioSamlLog] ALTER COLUMN [Message] varchar(MAX) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [BlanketSubmitTemp] ALTER COLUMN [FileContentIdentifier] nvarchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
ALTER TABLE [BlanketSubmitTemp] ALTER COLUMN [FileContent] ntext COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
ALTER TABLE [BlanketSubmitTemp] ALTER COLUMN [FileName] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
+0

el código de consulta real sería más útil que el resultado del ejemplo; no podemos decir que ninguna de esas columnas nvarchar tenga el doble de tamaño. –

0

bien he reescrito el código por Edosoft y ponerlo en un bucle para ejecutar las instrucciones reales de T-SQL .

-- **************** BEGIN INPUT ********************** 
USE [YourDBName] 

DECLARE @collation NVARCHAR(128) 
-- enter you collation name below 
SET @collation = N'Latin1_General_CI_AS' 
-- **************** END INPUT ************************ 

-- **************** BEGIN LOGIC ********************** 
DECLARE @sqlCode VARCHAR(2048) 

DECLARE myCursor CURSOR LOCAL FOR 
    SELECT 'ALTER TABLE [' + sys.objects.name + '] 
     ALTER COLUMN ['+ sys.columns.name + '] ' + sys.types.name + 
     CASE sys.types.name 
      WHEN 'text' THEN ' ' 
      WHEN 'ntext' THEN ' ' 
      ELSE '(' + RTRIM(
       CASE 
        WHEN sys.columns.max_length = -1 THEN 'MAX' 
        WHEN sys.columns.max_length > 4000 THEN 'MAX' 
        ELSE CONVERT(CHAR,sys.columns.max_length) 
       END) + ')' 
     END 
     + ' COLLATE ' + @collation + CASE sys.columns.is_nullable WHEN 0 THEN ' NOT NULL' ELSE ' NULL' END 
     FROM sys.columns , sys.objects , sys.types 
     WHERE sys.columns.object_id = sys.objects.object_id 
      AND sys.objects.TYPE = 'U' 
      AND sys.types.system_type_id = sys.columns.system_type_id 
      AND sys.columns.collation_name IS NOT NULL 
      AND sys.columns.collation_name <> @collation 
      AND NOT (sys.objects.NAME LIKE 'sys%') 
      AND NOT (sys.types.name LIKE 'sys%') 

OPEN myCursor 
FETCH NEXT FROM myCursor INTO @sqlCode 

WHILE @@FETCH_STATUS = 0 BEGIN 
    PRINT 'Executing: ' + @sqlCode 
    BEGIN TRY 
     EXEC(@sqlCode); 
     PRINT 'Done!' + CHAR(10) 
    END TRY 
    BEGIN CATCH 
     PRINT 'Error: ' + ERROR_MESSAGE() + CHAR(10) 
    END CATCH 
    FETCH NEXT FROM myCursor INTO @sqlCode 
END 

PRINT 'Finished!' 
-- **************** END LOGIC ********************** 

Si se obtiene el error algo similar a "No se puede crear una fila de tamaño 8075 que es mayor que el tamaño permitido fila máximo de 8060". Vuelva a generar la tabla para la que obtiene el error y vuelva a ejecutar el script anterior.

ALTER TABLE [dbo].[YourTableName] REBUILD 
Cuestiones relacionadas