No se puede resolver el conflicto de intercalación entre "SQL_Latin1_General_CP1_CI_AS" y "Latin1_General_CI_AS" en la operación igual a

342

Tengo el siguiente código

SELECT tA.FieldName As [Field Name],
       COALESCE(tO_A.[desc], tO_B.[desc], tO_C.Name, tA.OldVAlue) AS [Old Value],
       COALESCE(tN_A.[desc], tN_B.[desc], tN_C.Name, tA.NewValue) AS [New Value],
       U.UserName AS [User Name],
       CONVERT(varchar, tA.ChangeDate) AS [Change Date] 
  FROM D tA
       JOIN 
       [DRTS].[dbo].[User] U 
         ON tA.UserID = U.UserID
       LEFT JOIN 
       A tO_A 
         on tA.FieldName = 'AID' 
        AND tA.oldValue = CONVERT(VARCHAR, tO_A.ID)
       LEFT JOIN 
       A tN_A 
         on tA.FieldName = 'AID' 
        AND tA.newValue = CONVERT(VARCHAR, tN_A.ID)
       LEFT JOIN 
       B tO_B 
         on tA.FieldName = 'BID' 
        AND tA.oldValue = CONVERT(VARCHAR, tO_B.ID)
       LEFT JOIN 
       B tN_B 
         on tA.FieldName = 'BID' 
        AND tA.newValue = CONVERT(VARCHAR, tN_B.ID)
       LEFT JOIN 
       C tO_C 
         on tA.FieldName = 'CID' 
        AND tA.oldValue = tO_C.Name
       LEFT JOIN 
       C tN_C 
         on tA.FieldName = 'CID' 
        AND tA.newValue = tN_C.Name
 WHERE U.Fullname = @SearchTerm
ORDER BY tA.ChangeDate

Cuando ejecuto el código, obtengo el error pegado en el título después de agregar las dos combinaciones para la tabla C. Creo que esto puede tener algo que ver con el hecho de que estoy usando SQL Server 2008 y he restaurado una copia de esta base de datos en mi máquina que es 2005

jhowe
fuente

Respuestas:

307

Tiene una discrepancia de dos intercalaciones diferentes en su tabla. Puede verificar qué colaciones tiene cada columna en su (s) tabla (s) utilizando esta consulta:

SELECT
    col.name, col.collation_name
FROM 
    sys.columns col
WHERE
    object_id = OBJECT_ID('YourTableName')

Las clasificaciones son necesarias y se utilizan al ordenar y comparar cadenas. Por lo general, es una buena idea tener una clasificación única y única en toda su base de datos; no use diferentes clasificaciones dentro de una sola tabla o base de datos; solo está buscando problemas ...

Una vez que se haya conformado con una sola clasificación, puede cambiar las tablas / columnas que aún no coinciden con este comando:

ALTER TABLE YourTableName
  ALTER COLUMN OffendingColumn
    VARCHAR(100) COLLATE Latin1_General_CI_AS NOT NULL

Bagazo

ACTUALIZACIÓN: para encontrar los índices de texto completo en su base de datos, use esta consulta aquí:

SELECT
    fti.object_Id,
    OBJECT_NAME(fti.object_id) 'Fulltext index',
    fti.is_enabled,
    i.name 'Index name',
    OBJECT_NAME(i.object_id) 'Table name'
FROM 
    sys.fulltext_indexes fti
INNER JOIN 
    sys.indexes i ON fti.unique_index_id = i.index_id

Luego puede soltar el índice de texto completo usando:

DROP FULLTEXT INDEX ON (tablename)
marc_s
fuente
Gracias, Marc, ese es exactamente el tipo de cosas que estaba buscando, ¡una de las tablas era una recopilación diferente por alguna estúpida razón! Intentaré modificar la clasificación estándar y ver qué pasa.
jhowe
Marc: ahora obtengo esto: no se puede alterar o descartar la columna porque está habilitada para la búsqueda de texto completo.
jhowe
1
En ese caso, tendrá que dejar su índice de texto completo en esa tabla temporal, cambiar la intercalación, y luego volver a crear el índice de texto completo nuevo
marc_s
1
Gracias OP, estaba configurando una tabla temporal, así que esto ayudó, pero como no podía alterar la tabla, solo tenía que declararla correctamente para comenzar (como sigue): DECLARE @Table TABLE (CompareMessage VARCHAR (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)
FrostbiteXIII
1
¿Por qué no podemos tener 2 colaciones diferentes en la misma tabla? Si tengo 1 columna como nvarchar que solo necesita nombres en inglés y otra columna como letras rusas, otra columna como letras japonesas. ¿Cómo arreglo esto? ¿Hay una sola recopilación que cubra todo esto?
batmaci
854

Hago lo siguiente:

...WHERE 
    fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT

Funciona todo el tiempo. :)

Valquiria
fuente
68
Esta es una de las publicaciones más útiles en SO
Jamie Strauss
2
Utilicé esta solución porque estaba trabajando con dos sistemas heredados que usaban la misma base de datos, por lo que no estaba seguro de si cambiar la clasificación de las tablas interrumpiría la funcionalidad.
paolobueno
55
Si los mismos dos campos se usan juntos en otros lugares (comparaciones, uniones, fusión, etc.) asegúrese de que cada uno de ellos también tenga la clasificación especificada.
Zarepheth
55
Esto es extremadamente útil. Estoy usando una base de datos local y haciendo consultas en un servidor vinculado y tienen dos intercalaciones diferentes. Obviamente no puedo cambiar la intercalación en el servidor vinculado, y no quería cambiar la mía localmente, así que esta es absolutamente la mejor respuesta.
jtate
77
@ppumkin Si bien es una excelente solución, solo evita el problema, en lugar de resolverlo. A menos que desee cambiar la clasificación para cada consulta, lo cual es tedioso y no tiene un rendimiento óptimo. Si bien es una gran respuesta, la respuesta aceptada que siento es la mejor.
Rob
80

Use la collatecláusula en su consulta:

LEFT JOIN C tO_C on tA.FieldName = 'CID' AND tA.oldValue COLLATE Latin1_General_CI_AS = tO_C.Name  

Es posible que no tenga la sintaxis correcta (marque BOL), pero puede hacer esto para cambiar la intercalación sobre la marcha de la consulta; es posible que deba agregar la cláusula para cada combinación.

editar: me di cuenta de que esto no era del todo correcto: la cláusula de clasificación va después del campo que debe cambiar; en este ejemplo, cambié la clasificación en el tA.oldValuecampo.

Rayo
fuente
29

Identifique los campos para los que arroja este error y agregue lo siguiente: COLLATE DATABASE_DEFAULT

Hay dos tablas unidas en el campo Código:

...
and table1.Code = table2.Code
...

Actualice su consulta a:

...
and table1.Code COLLATE DATABASE_DEFAULT = table2.Code COLLATE DATABASE_DEFAULT
...
Palak.Maheria
fuente
Gracias. Cuando trabajamos en una base de datos prod, no siempre podemos cambiar la estructura de la base de datos como sugiere la respuesta aceptada.
Jennifer Wood
20

Esto puede suceder fácilmente cuando tiene 2 bases de datos diferentes y especialmente 2 bases de datos diferentes de 2 servidores diferentes. La mejor opción es cambiarlo a una colección común y hacer la unión o la comparación.

SELECT 
   *
FROM sd
INNER JOIN pd ON sd.SCaseflowID COLLATE Latin1_General_CS_AS = pd.PDebt_code COLLATE Latin1_General_CS_AS
Buzzzzzzz
fuente
13

@Valkyrie impresionante respuesta. Pensé que ponía aquí un caso cuando realizaba lo mismo con una subconsulta dentro de un procedimiento almacenado, ya que me preguntaba si su respuesta funciona en este caso, y fue genial.

...WHERE fieldname COLLATE DATABASE_DEFAULT in (
          SELECT DISTINCT otherfieldname COLLATE DATABASE_DEFAULT
          FROM ...
          WHERE ...
        )
Ikram M.
fuente
12

En donde los criterios agregan collate SQL_Latin1_General_CP1_CI_AS

Esto funciona para mi.

WHERE U.Fullname = @SearchTerm  collate SQL_Latin1_General_CP1_CI_AS
Carlos de Jesus Baez
fuente
6

La causa raíz es que la base de datos del servidor sql de la que tomó el esquema tiene una intercalación que difiere de su instalación local. Si no desea preocuparse por la clasificación, vuelva a instalar SQL Server localmente utilizando la misma clasificación que la base de datos SQL Server 2008.

Robert
fuente
Tuve el mismo problema, primero debe verificar la propiedad de su servidor y la base de datos para ver si tienen la misma clasificación
madan
5

error (No se puede resolver el conflicto de intercalación entre ...) generalmente ocurre al comparar datos de múltiples bases de datos.

como no puede cambiar la clasificación de las bases de datos ahora, use COLLATE DATABASE_DEFAULT.

----------
AND db1.tbl1.fiel1 COLLATE DATABASE_DEFAULT =db2.tbl2.field2 COLLATE DATABASE_DEFAULT 
chaminda welgamage
fuente
esto no es diferente de otra respuesta ya dada: stackoverflow.com/a/1607725/479251
Pac0
4

He tenido algo como esto antes, y lo que encontramos fue que la clasificación entre 2 tablas era diferente.

Comprueba que son iguales.

Adriaan Stander
fuente
4

Gracias a la respuesta de marc_s resolví mi problema original, inspirado para ir un paso más allá y publicar un enfoque para transformar una tabla completa a la vez: script tsql para generar las declaraciones de la columna alternativa:

DECLARE @tableName VARCHAR(MAX)
SET @tableName = 'affiliate'
--EXEC sp_columns @tableName
SELECT  'Alter table ' + @tableName + ' alter column ' + col.name
        + CASE ( col.user_type_id )
            WHEN 231
            THEN ' nvarchar(' + CAST(col.max_length / 2 AS VARCHAR) + ') '
          END + 'collate Latin1_General_CI_AS ' + CASE ( col.is_nullable )
                                                    WHEN 0 THEN ' not null'
                                                    WHEN 1 THEN ' null'
                                                  END
FROM    sys.columns col
WHERE   object_id = OBJECT_ID(@tableName)

gets: ALTER TABLE Affiliate ALTER COLUMN myTable NVARCHAR (4000) COLLATE Latin1_General_CI_AS NOT NULL

Admitiré estar desconcertado por la necesidad de col.max_length / 2 -

justSteve
fuente
Creo que la división entre dos es necesaria porque la longitud se almacena internamente como el número de bytes. Nvarchar toma dos bytes por carácter en lugar de uno como varchar.
Zebi
Gran trabajo, sin embargo, por encima del conteo de la dosis de la consulta para los tipos de datos ncha probablemente debido a col.max_length / 2 -
Imran
2

Para aquellos que tienen un script CREATE DATABASE (como fue mi caso) para la base de datos que está causando este problema, pueden usar el siguiente script CREATE para que coincida con la clasificación:

-- Create Case Sensitive Database
CREATE DATABASE CaseSensitiveDatabase
COLLATE SQL_Latin1_General_CP1_CS_AS -- or any collation you require
GO
USE CaseSensitiveDatabase
GO
SELECT *
FROM sys.types
GO
--rest of your script here

o

-- Create Case In-Sensitive Database
CREATE DATABASE CaseInSensitiveDatabase
COLLATE SQL_Latin1_General_CP1_CI_AS -- or any collation you require
GO
USE CaseInSensitiveDatabase
GO
SELECT *
FROM sys.types
GO
--rest of your script here

Esto aplica la clasificación deseada a todas las tablas, que era justo lo que necesitaba. Es ideal tratar de mantener la clasificación igual para todas las bases de datos en un servidor. Espero que esto ayude.

Más información en el siguiente enlace: SERVIDOR SQL: creación de una base de datos con una clasificación diferente en el servidor

pechar
fuente
2

He usado el contenido de este sitio para crear el siguiente script que cambia la recopilación de todas las columnas en todas las tablas:

CREATE PROCEDURE [dbo].[sz_pipeline001_collation] 
    -- Add the parameters for the stored procedure here
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;


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%' )

END
Chagbert
fuente
1
SYSCOLUMNS. La longitud de las columnas nvarchar debe dividirse por 2
palota
2

Verifique el nivel de intercalación que no coincide (servidor, base de datos, tabla, columna, carácter).

Si es el servidor, estos pasos me ayudaron una vez:

  1. Detener el servidor
  2. Encuentre su herramienta sqlservr.exe
  3. Ejecute este comando:

    sqlservr -m -T4022 -T3659 -s"name_of_insance" -q "name_of_collation"

  4. Inicie su servidor sql:

    net start name_of_instance

  5. Verifique nuevamente la clasificación de su servidor.

Aquí hay más información:

https://www.mssqltips.com/sqlservertip/3519/changing-sql-server-collation-after-installation/

WholeLifeLearner
fuente
2

Si esto ocurre en toda su base de datos, entonces es mejor cambiar la clasificación de la base de datos de la siguiente manera:

USE master;  
GO  
ALTER DATABASE MyOptionsTest  
COLLATE << INSERT COLATION REQUIRED >> ;  
GO  

--Verify the collation setting.  
SELECT name, collation_name  
FROM sys.databases  
WHERE name = N'<< INSERT DATABASE NAME >>';  
GO 

Referencia aquí

Justin
fuente
desafortunadamente, esto no cambiará la intercalación de las tablas existentes, sino solo el valor predeterminado para las tablas nuevas
RockScience
2

Se agregó código a la respuesta de @ JustSteve para tratar con las columnas varchar y varchar (MAX):

DECLARE @tableName VARCHAR(MAX)
SET @tableName = 'first_notes'
--EXEC sp_columns @tableName
SELECT  'Alter table ' + @tableName + ' alter column ' + col.name
        + CASE ( col.user_type_id )
            WHEN 231
            THEN ' nvarchar(' + CAST(col.max_length / 2 AS VARCHAR) + ') '
            WHEN 167
            THEN ' varchar(' + CASE col.max_length 
                                WHEN -1 
                                THEN 'MAX'
                                ELSE 
                                CAST(col.max_length AS VARCHAR)
                                end
                                 + ') '
          END + 'collate Latin1_General_CI_AS ' + CASE ( col.is_nullable )
                                                    WHEN 0 THEN ' not null'
                                                    WHEN 1 THEN ' null'
                                                  END
FROM    sys.columns col
WHERE   object_id = OBJECT_ID(@tableName)
Goner Doug
fuente
2

Para resolver este problema en la consulta sin cambiar ninguna de las bases de datos, puede convertir las expresiones en el otro lado del signo "=" con

COLLATE SQL_Latin1_General_CP1_CI_AS

como se sugiere aquí .

Lars Ericson
fuente
1

Tuve un error similar (No se puede resolver el conflicto de intercalación entre "SQL_Latin1_General_CP1_CI_AS" y "SQL_Latin1_General_CP1250_CI_AS" en la operación INTERSECT), cuando utilicé el controlador jdbc antiguo.

Resolví esto descargando un nuevo controlador de Microsoft o el proyecto de código abierto jTDS .

krzy-wa
fuente
1

Esto es lo que hicimos, en nuestra situación necesitamos una consulta ad hoc que se ejecute utilizando una restricción de fecha bajo demanda, y la consulta se define en una tabla.

Nuestra nueva consulta debe hacer coincidir los datos entre diferentes bases de datos e incluir datos de ambos.

Parece que COLLATION es diferente entre la base de datos que importa datos del sistema iSeries / AS400 y nuestra base de datos de informes; esto podría deberse a los tipos de datos específicos (como los acentos griegos en los nombres, etc.).

Entonces usamos la siguiente cláusula de unión:

...LEFT Outer join ImportDB..C4CTP C4 on C4.C4CTP COLLATE Latin1_General_CS_AS=CUS_Type COLLATE Latin1_General_CS_AS
Nuestro hombre en plátanos
fuente
1

Puede hacer esto fácilmente mediante 4 sencillos pasos

  1. copia de seguridad de su base de datos, por si acaso
  2. cambiar la clasificación de la base de datos: haga clic con el botón derecho en la base de datos, seleccione propiedades, vaya a las opciones y cambie la clasificación a la clasificación requerida.
  3. Genere un script para soltar y recrear todos los objetos de su base de datos: haga clic con el botón derecho en su base de datos, seleccione tareas, seleccione generar script ... (asegúrese de seleccionar Soltar y crear en las opciones avanzadas del asistente, también seleccione Esquema y datos)
  4. Ejecute el script generado anteriormente
Felix Mwiti Mugambi
fuente
1
INSERT INTO eSSLSmartOfficeSource2.[dbo].DeviceLogs  (DeviceId,UserId,LogDate,UpdateFlag) 
SELECT DL1.DeviceId ,DL1.UserId COLLATE DATABASE_DEFAULT,DL1.LogDate 
,0 FROM eSSLSmartOffice.[dbo].DeviceLogs DL1 
WHERE  NOT EXISTS 
(SELECT DL2.DeviceId ,DL2.UserId COLLATE DATABASE_DEFAULT
,DL2.LogDate ,DL2.UpdateFlag 
FROM eSSLSmartOfficeSource2.[dbo].DeviceLogs DL2    
WHERE  DL1.DeviceId =DL2.DeviceId
 and DL1.UserId collate  Latin1_General_CS_AS=DL2.UserId collate  Latin1_General_CS_AS
  and DL1.LogDate =DL2.LogDate )
Arati
fuente
0

Es posible que no tenga ningún problema de intercalación en su base de datos, pero si restaura una copia de su base de datos desde una copia de seguridad en un servidor con una intercalación diferente al origen, y su código está creando tablas temporales, esas tablas temporales heredarán la intercalación de el servidor y habría conflictos con su base de datos.

ajeh
fuente
0
ALTER DATABASE test2            --put your database name here
COLLATE Latin1_General_CS_AS    --replace with the collation you need
plantilla
fuente
0

Tenía un requerimiento similar; documentando mi enfoque aquí para cualquier persona con un escenario similar ...

Guión

  • Tengo una base de datos de una instalación limpia con las colaciones correctas.
  • Tengo otra base de datos que tiene las intercalaciones incorrectas.
  • Necesito actualizar el último para usar las colaciones definidas en el primero.

Solución

Use la comparación de esquemas de SQL Server (de SQL Server Data Tools / Visual Studio) para comparar el origen (instalación limpia) con el destino (el db con intercalación no válida).

En mi caso, comparé los dos DB directamente; aunque podría trabajar a través de un proyecto para permitirle ajustar manualmente las piezas entre ...

  • Ejecute Visual Studio
  • Crear un nuevo proyecto de datos de SQL Server
  • Haga clic en Herramientas, SQL Server, Nueva comparación de esquemas
  • Seleccione la base de datos de origen
  • Seleccione la base de datos de destino
  • Haga clic en opciones (⚙)
    • En Object Typesseleccione solo los tipos que le interesan (para mí solo eran Viewsy Tables)
    • Debajo General seleccionar:
      • Bloquear la posible pérdida de datos.
      • Deshabilitar y volver a activar los desencadenadores DDL
      • Ignorar la ruta del archivo del proveedor criptográfico
      • Ignorar ruta de archivo y archivo de registro
      • Ignorar tamaño de archivo
      • Ignorar la ubicación del grupo de archivos
      • Ignorar la ruta del archivo de catálogo de texto completo
      • Ignorar carcasa de palabras clave
      • Ignorar los SID de inicio de sesión
      • Ignorar identificadores citados
      • Ignorar ruta de por vida
      • Ignorar punto y coma entre declaraciones
      • Ignorar espacios en blanco
      • Módulo de actualización de script
      • Validación de script para nuevas restricciones
      • Verificar compatibilidad de colación
      • Verificar despliegue
  • Haga clic en Comparar
    • Desmarque los objetos marcados para su eliminación (NB: aún pueden tener problemas de intercalación; pero como no están definidos en nuestra fuente / plantilla db, no lo sabemos; de cualquier manera, no queremos perder cosas si estamos solo orientar cambios de colación). Puede desmarcar todo de una vez haciendo clic derecho en la DELETEcarpeta y seleccionando EXCLUDE.
    • Del mismo modo, excluya cualquier CREATEobjeto (aquí, dado que no existen en el objetivo, no pueden tener una clasificación incorrecta allí; si deberían existir es una pregunta para otro tema).
    • Haga clic en cada objeto debajo de CAMBIAR para ver la secuencia de comandos para ese objeto. Use el diff para asegurarse de que solo estamos cambiando la intercalación (cualquier otra diferencia detectada manualmente probablemente querrá excluir / manejar esos objetos manualmente).
  • Haga clic Updatepara empujar cambios

Esto todavía implica un esfuerzo manual (por ejemplo, comprobar que solo está afectando la clasificación), pero maneja las dependencias por usted.

También puede mantener un proyecto de base de datos del esquema válido para que pueda usar una plantilla universal para sus bases de datos en caso de que tenga más de 1 para actualizar, suponiendo que todas las bases de datos de destino terminen con el mismo esquema.

También puede usar buscar / reemplazar en los archivos en un proyecto de base de datos si desea modificar en masa la configuración allí (por ejemplo, para crear el proyecto a partir de la base de datos inválida usando la comparación de esquemas, enmendar los archivos del proyecto, luego alternar el origen / destino en el esquema se compara para enviar los cambios nuevamente a la base de datos

JohnLBevan
fuente