Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Se aplica a:SQL Server
Azure SQL Managed Instance
Varias propiedades afectan a la semántica de igualdad y al criterio de ordenación de los datos de texto, como son la distinción entre mayúsculas y minúsculas y de los acentos, y el idioma básico que se usa. Estas cualidades se expresan en SQL Server a través de la opción de intercalación de los datos. Para obtener una explicación más detallada sobre las intercalaciones, consulte Intercalación y soporte para Unicode.
Las intercalaciones se aplican no solo a los datos almacenados en las tablas de usuario, sino a todo el texto que se administra en SQL Server, como son los metadatos, los objetos temporales, los nombres de variables, etc. Su tratamiento difiere en las bases de datos independientes y en las dependientes. Este cambio no afecta a muchos usuarios, pero ayuda a proporcionar independencia de instancia y uniformidad. Pero esto también puede provocar cierta confusión y problemas para las sesiones que acceden a bases de datos contenidas y no contenidas.
El comportamiento de intercalación de las bases de datos independientes difiere de manera sutil del comportamiento de las bases de datos no independientes. Este comportamiento suele ser beneficioso y proporciona independencia de la instancia y simplicidad. Algunos usuarios pueden tener problemas, especialmente cuando una sesión accede a bases de datos contenidas y no contenidas.
En este artículo se aclara el contenido del cambio y se examinan las áreas en las que el cambio puede causar problemas.
Nota:
Para Azure SQL Database, las intercalaciones para las bases de datos independientes son diferentes. La intercalación de la base de datos y la intercalación del catálogo se pueden establecer durante la creación de la base de datos y no se pueden actualizar. Especifique una intercalación para los datos (COLLATE) y una intercalación de catálogo para los metadatos del sistema y los identificadores de objeto (CATALOG_COLLATION). Para más información, consulte CREATE DATABASE.
Bases de datos dependientes
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 usa para todos los metadatos de la base de datos y el valor predeterminado para todas las columnas de cadena dentro de la base de datos. Los usuarios pueden elegir una intercalación diferente para una columna en particular utilizando la cláusula COLLATE.
Ejemplo 1
Por ejemplo, si estuviéramos trabajando en Beijing, podríamos utilizar una intercalación china:
ALTER DATABASE MyDB
COLLATE Chinese_Simplified_Pinyin_100_CI_AS;
Ahora, si creamos una columna, su intercalación predeterminada es 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
Este es el conjunto de resultados.
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 almacenadas en tempdb. La intercalación de tempdb suele coincidir con la intercalación de la instancia, que no tiene que coincidir con la intercalación de la base de datos.
Ejemplo 2
Por ejemplo, tenga en cuenta la base de datos china anteriormente mostrada, cuando se usa en una instancia con una Latin1_General intercalación:
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 incompatibles:
SELECT T1_txt, T2_txt
FROM T1
INNER JOIN #T2
ON T1.T1_txt = #T2.T2_txt;
Este es el conjunto de resultados.
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 de igualdad.
Podemos corregir esto intercalando la tabla temporal explícitamente. SQL Server facilita esta tarea proporcionando 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
INNER JOIN #T2
ON T1.T1_txt = #T2.T2_txt;
Esta consulta ahora se ejecuta sin errores.
También podemos ver el comportamiento dependiente de la intercalación con variables. Considere la función siguiente:
CREATE FUNCTION f (@x INT)
RETURNS INT
AS
BEGIN
DECLARE @I AS INT = 1;
DECLARE @İ AS 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 return en @i no se puede enlazar ni a @I ni a @İ. En una intercalación Latin1_General sin distinción entre mayúsculas y minúsculas, @i enlaza a @I y la función devuelve 1. Pero en una intercalación turca sin distinción entre mayúsculas y minúsculas, @i enlaza a @İ y la función devuelve 2. Esto puede causar confusión en una base de datos que se mueva entre instancias con intercalaciones diferentes.
Bases de datos contenidas
Dado que uno de los objetivos de diseño de las bases de datos independientes es hacer que sean autodependientes, la dependencia de las intercalaciones de tempdb e instancia debe romperse. Para ello, las bases de datos independientes presentan el concepto de intercalación de catálogo. La intercalación de catálogo se utiliza para los objetos transitorios y los metadatos del sistema. Los detalles se proporcionan de la manera siguiente.
En una base de datos contenida, la intercalación de catálogo es Latin1_General_100_CI_AS_WS_KS_SC. Esta 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 intercalación de la base de datos se conserva, pero solo se usa como intercalación predeterminada para los datos del usuario. De forma predeterminada, la intercalación de la base de datos es igual que la de la base de datos model, pero el usuario puede cambiarla a través de un comando CREATE o ALTER DATABASE igual que en las bases de datos dependientes.
Una palabra clave nueva, CATALOG_DEFAULT, está disponible en la cláusula COLLATE. Esto se utiliza como acceso directo a la intercalación actual de los metadatos tanto en las bases de datos independientes como en las dependientes. Es decir, en una base de datos no contenida, CATALOG_DEFAULT devuelve la intercalación actual de la base de datos, ya que los metadatos se intercalan según 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 tanto en las bases de datos independientes como en las dependientes se resume en esta tabla:
| Elemento | Base de datos no contenida | Base de datos contenida |
|---|---|---|
| Datos de usuario (valor predeterminado) | DATABASE_DEFAULT |
DATABASE_DEFAULT |
| Datos temporales (valor predeterminado) |
tempdb ordenación |
DATABASE_DEFAULT |
| Metadatos | DATABASE_DEFAULT / CATALOG_DEFAULT |
CATALOG_DEFAULT |
| Metadatos temporales |
tempdb ordenación |
CATALOG_DEFAULT |
| Variables | Intercalación de instancia | CATALOG_DEFAULT |
| Etiquetas goto | Intercalación de instancia | CATALOG_DEFAULT |
| Nombres de cursor | Intercalación de instancia | CATALOG_DEFAULT |
En el ejemplo de la tabla temporal descrito previamente, podemos ver que este comportamiento de la intercalación elimina la necesidad de una cláusula COLLATE explícita en la mayor parte de los usos de las tablas temporales. En una base de datos independiente, este código se ejecuta ahora sin error, aun cuando las intercalaciones de instancia y base de datos difieren:
CREATE TABLE T1 (T1_txt NVARCHAR (MAX));
GO
CREATE TABLE #T2 (T2_txt NVARCHAR (MAX));
GO
SELECT T1_txt, T2_txt
FROM T1
INNER JOIN #T2
ON T1.T1_txt = #T2.T2_txt;
Esta consulta funciona porque ambos T1_txt y 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 sigue siendo contenida, debe permanecer dentro de la base de datos a la que se conectó. En este caso, el comportamiento es sencillo. Pero si una sesión cruza de un contexto contenido a uno no contenido, el comportamiento se vuelve más complejo, porque los dos conjuntos de reglas deben unirse. Esto puede ocurrir en una base de datos parcialmente contenida, ya que un usuario puede USE a otra base de datos. El siguiente principio administra la diferencia en las reglas de intercalación en este caso.
- La base de datos en la que el lote comienza determina el comportamiento de la intercalación de un lote.
Esta decisión se toma antes de que se emita cualquier comando, incluida una inicial USE. Es decir, si un lote comienza en una base de datos independiente, pero el primer comando es USE para una base de datos no independiente, el comportamiento de intercalación independiente se sigue usando para el lote. Dado este escenario, una referencia a una variable, por ejemplo, podría tener varios resultados posibles:
La referencia podría encontrar exactamente una coincidencia. En este caso, la referencia funciona sin error.
Es posible que la referencia no encuentre una coincidencia en la intercalación actual, donde anteriormente había una coincidencia. Esto genera un error que indica que la variable no existe, aunque aparentemente se creó.
La referencia podría encontrar varias coincidencias que originalmente eran distintas. Esto también genera un error.
Esto se ilustra con algunos ejemplos. Para estos casos, se supone que hay una base de datos parcialmente contenida denominada MyCDB con la intercalación de base de datos configurada en la intercalación predeterminada, Latin1_General_100_CI_AS_WS_KS_SC. Se supone que la ordenación de la instancia es Latin1_General_100_CS_AS_WS_KS_SC. Las dos intercalaciones solo difieren en la distinción de mayúsculas y minúsculas.
Ejemplo 1
El siguiente ejemplo ilustra 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:
Este es el conjunto de resultados.
x
-----------
1
En este caso, el #a identificado enlaza en la intercalación del catálogo sin distinción entre mayúsculas y minúsculas y la intercalación de la instancia con distinción entre mayúsculas y minúsculas, y el código se ejecuta bien.
Ejemplo 2
En el siguiente ejemplo se ilustra el caso en el que la referencia no encuentra una coincidencia en la intercalación actual, donde antes sí la había.
USE MyCDB;
GO
CREATE TABLE #a (x INT);
INSERT INTO #A VALUES (1);
GO
Aquí, #A enlaza a #a en la intercalación predeterminada sin distinción entre mayúsculas y minúsculas, y la inserción funciona,
Este es el conjunto de resultados.
(1 row(s) affected)
Pero si continuamos el script...
USE master;
GO
SELECT * FROM #A;
GO
Obtenemos un error al intentar enlazar #A en la intercalación de la instancia con distinción entre mayúsculas y minúsculas;
Este es el conjunto de resultados.
Msg 208, Level 16, State 0, Line 2
Invalid object name '#A'.
Ejemplo 3
El siguiente ejemplo ilustra el caso en el que la referencia encuentra varias coincidencias que eran distintas originalmente. Primero, comenzamos 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
Esta consulta se realiza correctamente, ya que las tablas son distintas en esta intercalación:
Este es el conjunto de resultados.
(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
Este es el conjunto de resultados.
Msg 12800, Level 16, State 1, Line 2
The reference to temp table name #a is ambiguous and cannot be resolved. Possible candidates are #a and #A.