GuilleSQL :: Microsoft SQL Server, SSIS, y más !!

SQL Server FAQ: ¿Qué es la Intercalación (Collation) en SQL Server? ¿Es posible cambiar la Intercalación de una base de datos?

Volver a: [SQL Server FAQ :: Preguntas y Respuestas Frecuentes de SQL Server :: Manual SQL Server]


Este capítulo explica el concepto de Intercalación (Collation) de las bases de datos SQL Server. Se explica las consideraciones de configuración de Intercalación (Collation) a nivel de instancia de SQL Server (es decir, de las bases de datos del sistema), peculiaridades de la configuración de Instancia a nivel de de base de datos (distintas bases de datos pueden utilizar una Intercalación diferente), etc. También se explica cómo cambiar la intercalación de una columna (ALTER TABLE ALTER COLUMN COLLATE), cómo cambiar la intercalación de una base de datos, la utilización de la función fn_helpcollations, la utilización de la palabra clave COLLATE en la cláusula WHERE, etc.

El concepto de Intercalación (Collation) hace referencia al patrón de bits utilizado para representar/almacenar cada carácter, y en consecuencia también se refiere a las reglas utilizadas para ordenar y comparar caracteres. Evidentemente, se trata de un concepto que afecta sólo a los campos de texto.

En la instalación de SQL Server se indica la Intercalación (Collation) de la Instancia, que definirá la intercalación utilizada por las bases de datos del sistema. De aquí podemos inferir (de hecho, es así), que todas las bases de datos del sistema utilizan la misma Intercalación (Collation). Como anécdota, en una ocasión me encontré con una Instancia que durante un proceso de recuperación de una catástrofe, dejaron las bases de datos master y msdb con una intercalación, y las bases de datos model y tempdb con una intercalación diferente (reinstalarón SQL Server con una Intercalación distinta a la original, y posteriormente, recuperaron master y msdb). La Instancia funcionaba aparentemente bien, pero empezamos a encontrar que algunas tareas realizadas con el Enterprise Manager (era una instalación de SQL Server 2000 Enterprise), producía un error, como era el caso de agregar un usuario a una base de datos. Investigando (con trazas, y un poquitín de tiempo), encontramos que Enterprise Manager utilizaba para dicha acción un procedimiento almacenado que creaba una tabla temporal (sobre tempdb, evidentemente) con datos obtenidos de master, y seguidamente hacía un join a través de campos de texto entre dicha tabla temporal y otras tablas de master. El error evidente: La intercalación era distinta, y dicho procedimiento almacenado no se podía ejecutar. De aquí podemos sacar como moraleja, la importancia de tener bien identificada y documentada la Intercalación utilizada por nuestras Instancias y bases de datos de SQL Server, tanto para recuperación de catástrofes como en otros procesos como migraciones y consolidaciones de servidores, etc.

Otra particularidad de la Intercalación (Collation) de una Instancia de SQL Server, es que siempre que se cree una base de datos, por defecto se creará utilizando la Intercalación de la Instancia, excepto que especifiquemos lo contrario.

Aunque la Intercalación (Collation) de todas las bases de datos del sistema debe ser la misma, la Intercalación (Collation) de cada base de datos de usuario puede ser diferente, es decir, podemos tener una base de datos utilizando una Intercalación por requisitos de la aplicación que la utiliza, y otra base de datos de la misma Instancia de SQL Server, utilizando una Intercalación diferente, siendo ésta una configuración natural y habitual.

Es importante tener en cuenta que la Intercalación (Collation) de una base de datos, sólo afecta a:

  • La Intercalación de las tablas y objetos del sistema.
  • La Intercalación de las nuevas tablas y objetos que se creen en la base de datos. Esto es debido, a que si no se especifica de forma explícita la Intercalación deseada en la sentencia CREATE correspondiente, se tomará por defecto la Intercalación de la base de datos.

Es posible cambiar la Intercalación de una base de datos utilizando el comando ALTER DATABASE COLLATE (ej: ALTER DATABASE miBaseDatos COLLATE Modern_Spanish_CI_AS). Sin embargo, lo más probable es que no consigamos lo que creemos estar consiguiendo (ya me decían de pequeño: "hay que tener cuidado con lo que se pide"... jeje ;-). El comando ALTER DATABASE COLLATE se limita a cambiar la Intercalación (Collation) de las tablas del sistema de la base de datos y el valor de Intercalación que por defecto utilizarán los nuevos objetos que se creen sin especificar de forma explícita la Intercalación deseada. Sin embargo, ALTER DATABASE COLLATE no cambiará la intercalación de las tablas existentes. Si deseamos cambiar la Intercalación de una base de datos y de todos sus objetos, una solución es crear una nueva base de datos con la Intercalación deseada, generar el Script de creación de objetos de la base de datos original (sin especificar la Intercalación en dicho Script), ejecutar el Script en la nueva base de datos, y cargar los datos desde la base de datos original utilizando el Asistente de Importación de SQL Server (Import Data). Esta no es la única opción posible, pero en general, es quizás la más apropiada (en general... en cada caso específico, habría que ver). También podemos crear a mano las descargas y cargas de las tablas, con la utilidad BCP.EXE y/o con el comando BULK INSERT, pero a fin de cuentas, esto es lo que hará el Asistente de Importación de forma automática para todas las tablas, así que para qué perder el tiempo, ¿no?. También cabe la posibilidad de utilizar el comando ALTER TABLE ALTER COLUMN COLLATE (ej: ALTER TABLE Facturas ALTER COLUMN ClientID CHAR(10) COLLATE Modern_Spanish_CI_AS), sin embargo, en el momento en que el campo que deseamos alterar tenga definido sobre él un índice, una clave externa, etc., la ejecución de dicho ALTER TABLE será fallida, produciéndose un error como el siguiente:

Server: Msg 5074, Level 16, State 8, Line 1
The object 'PK_Facturas' is dependent on column 'cod'.
Server: Msg 4922, Level 16, State 1, Line 1
ALTER TABLE ALTER COLUMN cod failed because one or more objects access this column.

Evidentemente, eliminar los índices, claves externas, etc., y luego volver a crearlos, es un trabajo extra que tendremos que considerar si realmente nos interesa asumir.

También es posible definir un valor de Intercalación distinto para cada campo de cada tabla. De éste modo, podríamos tener en cada campo de texto de cada tabla, una Intercalación distinta, lo cual se trata de una posibilidad que ofrece gran flexibilidad. Sin embargo, puede producirse un efecto colateral: en algunas instalaciones que he conocido, me he encontrado que en una misma base de datos conviven tablas con diferentes intercalaciones, no porque se desee, sino por descuido de los programadores. Al principio no hay problema, hasta que llega ese momento en el cual deseamos hacer alguna consulta y no podemos (ej: un JOIN entre dos campos de texto con distintas intercalaciones sin utilizar COLLATE en dicho JOIN).

Para conocer las distintas Intercalaciones que tenemos disponibles, podemos consultar la función del sistema fn_helpcollations (ej: select * from ::fn_helpcollations()).

En la práctica, habitualmente al crear una base de datos se crea con la Intercalación por defecto de la Instancia (que ya vimos que se determinó en la instalación de la Instancia), de tal modo que al crear las tablas en la base de datos, sus campos de texto se crean con la Intercalación por defecto de la base de datos. Esto, siempre y cuando no se especifique de forma explícita la Intercalación en las sentencias DDL.

Otro problema habitual relacionado con la Intercalación (Collation), es cuando deseamos realizar consultas entre tablas realizando un JOIN entre campos de texto con distinta Intercalación. Esto no es posible de realizar (obtendremos un error como Cannot resolve collation conflict for equal to operation). Sin embargo, cabe la posibilidad de utilizar la cláusula COLLATE en el JOIN, como si estuviésemos realizando un Casting (en vez de convertir entre tipos de datos, convertimos entre Intercalaciones). Así, podríamos utilizar una cláusula WHERE similar a la del siguiente ejemplo: WHERE a.client_name = b.client_name COLLATE Modern_Spanish_CI_AS.

Volver a: [SQL Server FAQ :: Preguntas y Respuestas Frecuentes de SQL Server :: Manual SQL Server]



Comentarios

SusanMR - 08/12/2017 (UTC)
Muy buen post, explicado con total claridad y con buenos ejemplos, muchas gracias por tu aporte, entendí lo que estaba buscando.


OscarWVD - 08/09/2019 (UTC)
Hola amigo. Muy interesante tu explicación.
Dime, ¿tienes algún post donde explicas para en qué casos se debe utilizar una u otra intercalación? Con ejemplos y todo.
Gracias.



Miembros de
Miembros de GITCA (Global IT Community Association)

Menu de Usuario
  Iniciar Sesión
  Registrarse
  Restablecer Contraseña
  Ventajas de Registrarse

Acerca de
  Contigo desde Oct 2007
  771 usuarios registrados
  86146 pageloads/mes
  Ranking Alexa 498160

Social Networks
Sigue a Portal GuilleSQL en Linkedin !!
Sigue a Portal GuilleSQL en Twitter !!



Archivo

Marzo de 2019 (1)
Octubre de 2018 (1)
Julio de 2018 (1)
Junio de 2018 (4)
Mayo de 2018 (5)
Abril de 2018 (3)
Marzo de 2018 (2)
Febrero de 2018 (7)
Enero de 2018 (1)
Diciembre de 2017 (15)
Noviembre de 2017 (7)
Junio de 2017 (3)
Mayo de 2017 (1)
Marzo de 2017 (3)
Enero de 2017 (4)
Junio de 2016 (1)
Mayo de 2016 (2)
Abril de 2016 (2)
Septiembre de 2015 (2)
Agosto de 2015 (2)
Junio de 2015 (10)
Mayo de 2015 (4)
Abril de 2015 (8)
Marzo de 2015 (11)
Octubre de 2014 (3)
Septiembre de 2014 (7)
Agosto de 2014 (5)
Julio de 2014 (2)
Mayo de 2014 (4)
Abril de 2014 (4)
Marzo de 2014 (4)
Febrero de 2014 (1)
Enero de 2014 (5)
Diciembre de 2013 (8)
Noviembre de 2013 (2)
Octubre de 2013 (7)
Septiembre de 2013 (6)
Agosto de 2013 (1)
Julio de 2013 (6)
Junio de 2013 (11)
Mayo de 2013 (7)
Abril de 2013 (6)
Febrero de 2013 (5)
Enero de 2013 (7)
Diciembre de 2012 (12)
Noviembre de 2012 (13)
Octubre de 2012 (5)
Septiembre de 2012 (3)
Agosto de 2012 (6)
Julio de 2012 (4)
Junio de 2012 (1)
Mayo de 2012 (2)
Abril de 2012 (7)
Marzo de 2012 (16)
Febrero de 2012 (9)
Enero de 2012 (5)
Diciembre de 2011 (10)
Noviembre de 2011 (10)
Octubre de 2011 (4)
Septiembre de 2011 (5)
Agosto de 2011 (2)
Julio de 2011 (2)
Junio de 2011 (4)
Mayo de 2011 (2)
Abril de 2011 (6)
Marzo de 2011 (4)
Febrero de 2011 (10)
Enero de 2011 (5)
Diciembre de 2010 (6)
Noviembre de 2010 (4)
Octubre de 2010 (8)
Septiembre de 2010 (4)
Agosto de 2010 (1)
Julio de 2010 (3)
Mayo de 2010 (5)
Abril de 2010 (6)
Marzo de 2010 (8)
Febrero de 2010 (3)
Enero de 2010 (1)
Diciembre de 2009 (9)
Noviembre de 2009 (14)
Octubre de 2009 (2)
Septiembre de 2009 (8)
Agosto de 2009 (2)
Julio de 2009 (10)
Junio de 2009 (9)
Mayo de 2009 (10)
Abril de 2009 (9)
Marzo de 2009 (3)
Febrero de 2009 (2)
Enero de 2009 (3)
Noviembre de 2008 (2)
Octubre de 2008 (2)
Septiembre de 2008 (2)
Agosto de 2008 (5)
Julio de 2008 (5)
Junio de 2008 (1)
Mayo de 2008 (3)
Abril de 2008 (2)
Marzo de 2008 (2)
Febrero de 2008 (2)
Enero de 2008 (5)
Noviembre de 2007 (2)
Octubre de 2007 (2)






Copyright © 2007 GuilleSQL, todos los derechos reservados.