Compartir a través de


Intercalaciones contenidas de base de datos

Varias propiedades afectan a la semántica de ordenación e igualdad de los datos textuales, incluida la distinción entre mayúsculas y minúsculas, la distinción de énfasis y el idioma base que se usa. Estas cualidades se expresan en SQL Server mediante la elección de intercalación para los datos. Para obtener una explicación más detallada de las intercalaciones en sí mismas, consulte Compatibilidad con intercalación y Unicode.

Las intercalaciones se aplican no solo a los datos almacenados en tablas de usuario, sino a todo el texto manejado por SQL Server, incluidos metadatos, objetos temporales, nombres de variables, etc. El manejo de esto varía entre las bases de datos contenidas y no contenidas. Este cambio no afectará a muchos usuarios, pero ayuda a proporcionar independencia de instancias y uniformidad. Pero esto también puede provocar alguna confusión, así como problemas para las sesiones que acceden tanto a bases de datos contenidas como no contenidas.

En este tema se aclara el contenido del cambio y se examinan las áreas en las que el cambio puede causar problemas.

Bases de datos no encapsuladas

Todas las bases de datos tienen una intercalación predeterminada (que se puede establecer al crear o modificar una base de datos). Esta intercalación se utiliza para todos los metadatos de la base de datos, así como como predeterminado para todas las columnas de texto dentro de la base de datos. Los usuarios pueden elegir una intercalación diferente para cualquier columna determinada mediante la COLLATE cláusula .

Ejemplo 1

Por ejemplo, si estuviéramos trabajando en Beijing, podríamos usar una ordenación china:

ALTER DATABASE MyDB COLLATE Chinese_Simplified_Pinyin_100_CI_AS;  

Ahora, si creamos una columna, su intercalación predeterminada será esta intercalación china, pero podemos elegir otra si queremos:

CREATE TABLE MyTable  
      (mycolumn1 nvarchar,  
      mycolumn2 nvarchar COLLATE Frisian_100_CS_AS);  
GO  
SELECT name, collation_name  
FROM sys.columns  
WHERE name LIKE 'mycolumn%' ;  
GO  

El conjunto de resultados es el siguiente:

name            collation_name  
--------------- ----------------------------------  
mycolumn1       Chinese_Simplified_Pinyin_100_CI_AS  
mycolumn2       Frisian_100_CS_AS  

Esto parece relativamente sencillo, pero surgen varios problemas. Dado que la intercalación de una columna depende de la base de datos en la que se crea la tabla, surgen problemas con el uso de tablas temporales que se almacenan en tempdb. La intercalación de tempdb generalmente coincide con la intercalación de la instancia, aunque no necesariamente con la de la base de datos.

Ejemplo 2

Por ejemplo, considere la base de datos (china) anterior cuando se utiliza en una instancia con una intercalación Latin1_General.

CREATE TABLE T1 (T1_txt nvarchar(max)) ;  
GO  
CREATE TABLE #T2 (T2_txt nvarchar(max)) ;  
GO  

A primera vista, estas dos tablas tienen el mismo esquema, pero dado que las intercalaciones de las bases de datos difieren, los valores son realmente incompatibles:

SELECT T1_txt, T2_txt  
FROM T1   
JOIN #T2   
    ON T1.T1_txt = #T2.T2_txt  

El conjunto de resultados es el siguiente:

Mensaje 468, nivel 16, estado 9, línea 2

No se puede resolver el conflicto de intercalación entre "Latin1_General_100_CI_AS_KS_WS_SC" y "Chinese_Simplified_Pinyin_100_CI_AS" en la operación igual a.

Podemos corregirlo ordenando explícitamente la tabla temporal. SQL Server facilita esto al proporcionar la DATABASE_DEFAULT palabra clave para la COLLATE cláusula .

CREATE TABLE T1 (T1_txt nvarchar(max)) ;  
GO  
CREATE TABLE #T2 (T2_txt nvarchar(max) COLLATE DATABASE_DEFAULT);  
GO  
SELECT T1_txt, T2_txt  
FROM T1   
JOIN #T2   
    ON T1.T1_txt = #T2.T2_txt ;  

Esto ahora se ejecuta sin error.

También podemos ver el comportamiento dependiente de la ordenación con variables. Tenga en cuenta la siguiente función:

CREATE FUNCTION f(@x INT) RETURNS INT  
AS BEGIN   
      DECLARE @I INT = 1  
      DECLARE @?? INT = 2  
      RETURN @x * @i  
END;  

Esta es una función bastante peculiar. En una intercalación que distingue mayúsculas de minúsculas, la cláusula de devolución @i no se puede enlazar a @I ni a @??. En una intercalación de Latin1_General sin distinción entre mayúsculas y minúsculas, @i se vincula a @I y la función devuelve 1. Pero en una intercalación turca que no distingue mayúsculas de minúsculas, @i enlaza con @??, y la función devuelve 2. Esto puede causar daños en una base de datos que se mueve entre instancias con intercalaciones diferentes.

Bases de datos independientes

Dado que un objetivo de diseño de las bases de datos independientes es hacer que se autocontenan, se debe romper la dependencia de la instancia y tempdb las intercalaciones. Para ello, las bases de datos contenidas presentan el concepto de intercalación del catálogo. La intercalación de catálogo se usa para los metadatos del sistema y los objetos transitorios. A continuación se proporcionan los detalles.

En una base de datos contenida, la intercalación del catálogo Latin1_General_100_CI_AS_WS_KS_SC. Esta configuración de intercalación es la misma para todas las bases de datos contenidas en todas las instancias de SQL Server y no se puede cambiar.

La clasificación de la base de datos se mantiene, pero solo se utiliza como clasificación predeterminada para los datos de los usuarios. De forma predeterminada, la intercalación de base de datos es igual a la intercalación de base de datos modelo, pero el usuario puede cambiarla a través de un CREATE comando o ALTER DATABASE como con bases de datos no independientes.

Hay disponible una palabra clave nueva, CATALOG_DEFAULT, en la COLLATE cláusula . Se usa como acceso rápido a la intercalación actual de metadatos en bases de datos contenidas y no contenidas. Es decir, en una base de datos no contenida, CATALOG_DEFAULT devolverá la intercalación actual de la base de datos, ya que los metadatos se intercalan usando la intercalación de la base de datos. En una base de datos independiente, estos dos valores pueden ser diferentes, ya que el usuario puede cambiar la intercalación de la base de datos para que no coincida con la intercalación del catálogo.

El comportamiento de varios objetos en bases de datos no contenidos y contenidos se resume en esta tabla:

Elemento Base de datos no contenida Base de datos contenida
Datos de usuario (valor predeterminado) BASE_DE_DATOS_POR_DEFECTO BASE_DE_DATOS_POR_DEFECTO
Datos temporales (valor predeterminado) Intercalación de TempDB BASE_DE_DATOS_POR_DEFECTO
Metadatos BASE_DE_DATOS_DEFECTO/CATÁLOGO_DEFECTO CATÁLOGO_POR_DEFECTO
Metadatos temporales Intercalación de tempdb CATÁLOGO_PREDEFINIDO
variables Intercalación de instancia CATALOG_DEFAULT
Etiquetas goto Intercalación de instancia CATALOG_DEFAULT
Nombres de cursor Intercalación de instancias CATÁLOGO_POR_DEFECTO

Si describimos el ejemplo de tabla temporal anteriormente mencionado, podemos ver que este comportamiento de intercalación elimina la necesidad de una cláusula explícita COLLATE en la mayoría de las tablas temporales. En una base de datos independiente, este código ahora se ejecuta sin errores, incluso si las intercalaciones de la base de datos y de la instancia difieren:

CREATE TABLE T1 (T1_txt nvarchar(max)) ;  
GO  
CREATE TABLE #T2 (T2_txt nvarchar(max));  
GO  
SELECT T1_txt, T2_txt  
FROM T1   
JOIN #T2   
    ON T1.T1_txt = #T2.T2_txt ;  

Esto funciona porque tanto T1_txt como T2_txt se intercalan en la intercalación de base de datos de la base de datos contenida.

Cruce entre contextos confinados y no confinados

Siempre que una sesión de una base de datos independiente permanezca contenida, debe permanecer dentro de la base de datos a la que se ha conectado. En este caso, el comportamiento es muy sencillo. Pero si una sesión cruza entre contextos contenidos y no contenidos, el comportamiento se vuelve más complejo, ya que los dos conjuntos de reglas deben ser conectados. Esto puede ocurrir en una base de datos parcialmente contenida, ya que un usuario puede USE a otra base de datos. En este caso, la diferencia en las reglas de ordenación se controla mediante el siguiente principio.

  • El comportamiento de intercalación de un lote viene determinado por la base de datos en la que comienza el lote.

Tenga en cuenta que esta decisión se toma antes de que se emita cualquier comando, incluido un inicial USE. Es decir, si un lote comienza en una base de datos contenida, pero el primer comando es para USE una base de datos no contenida, el comportamiento de intercalación contenida se seguirá usando para el lote. Dado esto, una referencia a una variable, por ejemplo, puede tener varios resultados posibles:

  • La referencia puede encontrar exactamente una coincidencia. En este caso, la referencia funcionará sin error.

  • Es posible que la referencia no encuentre una coincidencia en la clasificación actual, donde había una antes. Esto generará un error que indica que la variable no existe, aunque aparentemente se creó.

  • La referencia puede encontrar varias coincidencias que en un principio eran distintas. Esto también generará un error.

Lo mostraremos con algunos ejemplos. Para estos, se supone que hay una base de datos parcialmente contenida denominada MyCDB con su intercalación de base de datos configurada en la intercalación predeterminada, Latin1_General_100_CI_AS_WS_KS_SC. Se supone que la intercalación de instancia es Latin1_General_100_CS_AS_WS_KS_SC. Las dos intercalaciones solo difieren en sensibilidad a mayúsculas.

Ejemplo 1

En el ejemplo siguiente se muestra el caso en el que la referencia encuentra exactamente una coincidencia.

USE MyCDB;  
GO  
  
CREATE TABLE #a(x int);  
INSERT INTO #a VALUES(1);  
GO  
  
USE master;  
GO  
  
SELECT * FROM #a;  
GO  
  
Results:  
  

El conjunto de resultados es el siguiente:

x  
-----------  
1  

En este caso, el #a identificado enlaza tanto en la intercalación de catálogo sin distinción entre mayúsculas y minúsculas como en la intercalación de instancia que distingue mayúsculas de minúsculas y el código funciona.

Ejemplo 2

En el siguiente ejemplo se ilustra el caso en el que la referencia no encuentra una coincidencia en la ordenación actual, donde anteriormente había una.

USE MyCDB;  
GO  
  
CREATE TABLE #a(x int);  
INSERT INTO #A VALUES(1);  
GO  

Aquí, el #A se enlaza a #a en un sistema de colación predeterminado sin distinguir entre mayúsculas y minúsculas, y la inserción funciona.

El conjunto de resultados es el siguiente:

(1 row(s) affected)  

Pero si seguimos el script...

USE master;  
GO  
  
SELECT * FROM #A;  
GO  

Se produce un error al intentar enlazar a #A en la intercalación de instancia que distingue mayúsculas de minúsculas;

El conjunto de resultados es el siguiente:

Mensaje 208, nivel 16, estado 0, línea 2

Nombre de objeto "#A" no válido.

Ejemplo 3

En el ejemplo siguiente se muestra el caso en el que la referencia encuentra varias coincidencias que originalmente eran distintas. En primer lugar, empezamos en tempdb (que tiene la misma intercalación con distinción entre mayúsculas y minúsculas que nuestra instancia) y ejecutamos las siguientes instrucciones.

USE tempdb;  
GO  
  
CREATE TABLE #a(x int);  
GO  
CREATE TABLE #A(x int);  
GO  
INSERT INTO #a VALUES(1);  
GO  
INSERT INTO #A VALUES(2);  
GO  

Esto se realiza correctamente, ya que las tablas son distintas en esta intercalación:

El conjunto de resultados es el siguiente:

(1 row(s) affected)  
(1 row(s) affected)  

Sin embargo, si pasamos a nuestra base de datos independiente, encontramos que ya no podemos enlazar a estas tablas.

USE MyCDB;  
GO  
SELECT * FROM #a;  
GO  

El conjunto de resultados es el siguiente:

Mensaje 12800, nivel 16, estado 1, línea 2

La referencia al nombre de tabla temporal "#a" es ambigua y no se puede resolver. Los posibles candidatos son "#a" y "#A".

Conclusión

El comportamiento de intercalación de las bases de datos contenidas difiere del de las bases de datos no contenidas. Este comportamiento suele ser beneficioso, lo que proporciona independencia de instancia y simplicidad. Algunos usuarios pueden tener problemas, especialmente cuando una sesión accede a bases de datos contenidas y no contenidas.

Véase también

Bases de datos independientes