Não é possível resolver o conflito de agrupamento entre "SQL_Latin1_General_CP1_CI_AS" e "Latin1_General_CI_AS" na operação igual a


341

eu tenho o seguinte 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

Ao executar o código, estou recebendo o erro colado no título após adicionar as duas associações à tabela C. Acho que isso pode ter algo a ver com o fato de estar usando o SQL Server 2008 e ter restaurado uma cópia desse banco de dados para minha máquina que é 2005.

Respostas:


306

Você tem uma incompatibilidade de duas ordenações diferentes na sua tabela. Você pode verificar quais agrupamentos cada coluna em suas tabelas possui usando esta consulta:

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

Os agrupamentos são necessários e usados ​​ao solicitar e comparar seqüências de caracteres. Geralmente, é uma boa idéia ter um agrupamento único e exclusivo usado em todo o banco de dados - não use agrupamentos diferentes em uma única tabela ou banco de dados - você está apenas pedindo problemas ...

Depois de escolher um único agrupamento, você pode alterar as tabelas / colunas que ainda não correspondem usando este comando:

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

Marc

UPDATE: para encontrar os índices de texto completo no seu banco de dados, use esta consulta aqui:

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

Você pode soltar o índice de texto completo usando:

DROP FULLTEXT INDEX ON (tablename)

Obrigado marc, que é exatamente o tipo de coisa que eu estava procurando, uma das tabelas foi agrupada por algum motivo estúpido! Vou tentar alterar para o agrupamento padrão e ver o que acontece.
jhowe

marc Estou obtendo isso agora: não é possível alterar ou soltar a coluna porque ela está ativada para a pesquisa de texto completo.
jhowe

11
Nesse caso, você precisa soltar o seu índice de texto completo nessa tabela temporariamente, alterar o agrupamento, e, em seguida, re-criar o índice de texto completo novamente
marc_s

11
Obrigado OP, eu estava configurando uma tabela temporária para que isso ajudasse, mas como não consegui alterar a tabela, eu precisava declara-la corretamente para começar (a seguir): DECLARE @Table TABLE (CompareMessage VARCHAR (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)
FrostbiteXIII

11
por que não podemos ter 2 agrupamentos diferentes na mesma mesa. Se eu tiver uma coluna como nvarchar, que precisa apenas de nomes em inglês e outra coluna como letras russas, outra coluna como letras japonesas. Como faço para organizar isso? Existe um único agrupamento que cobre tudo isso?
batmaci

854

Eu faço o seguinte:

...WHERE 
    fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT

Funciona sempre. :)


68
Esta é uma das postagens mais úteis sobre SO
Jamie Strauss

2
Usei esta solução porque estava trabalhando com dois sistemas legados usando o mesmo banco de dados, então não tinha certeza se a alteração do agrupamento das tabelas quebraria a funcionalidade.
precisa saber é o seguinte

5
Se os mesmos dois campos forem usados ​​juntos em outros lugares (comparações, uniões, coalescência, etc ...), verifique se cada um deles também possui o agrupamento especificado.
Zarepheth 17/02/14

5
Isso é extremamente útil. Estou usando um banco de dados local e consultando um servidor vinculado e eles têm dois agrupamentos diferentes. Obviamente, não posso alterar o agrupamento no servidor vinculado e não queria alterar o meu localmente, portanto essa é absolutamente a melhor resposta.
jtate

7
@ppumkin Embora seja uma ótima solução, ela ainda evita o problema, em vez de resolvê-lo. A menos que você queira alterar o agrupamento de cada consulta, o que é tedioso e não apresenta um desempenho ideal. Embora seja uma ótima resposta, a resposta aceita é a melhor.
Rob

80

Use a collatecláusula na sua consulta:

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

Talvez eu não tenha a sintaxe exatamente correta (verifique BOL), mas você pode fazer isso para alterar o agrupamento imediatamente para a consulta - pode ser necessário adicionar a cláusula para cada associação.

editar: percebi que isso não estava certo - a cláusula de agrupamento segue o campo que você precisa alterar - neste exemplo, alterei o agrupamento no tA.oldValuecampo.


29

Identifique os campos para os quais está lançando esse erro e adicione o seguinte a eles: COLLATE DATABASE_DEFAULT

Há duas tabelas unidas no campo Código:

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

Atualize sua consulta para:

...
and table1.Code COLLATE DATABASE_DEFAULT = table2.Code COLLATE DATABASE_DEFAULT
...

Obrigado. Ao trabalhar em um banco de dados prod, nem sempre podemos alterar a estrutura do banco de dados, conforme sugerido pela resposta aceita.
21417 Jennifer Wood

20

Isso pode acontecer facilmente quando você tem 2 bancos de dados diferentes e especialmente 2 bancos de dados diferentes de 2 servidores diferentes. A melhor opção é alterá-lo para uma coleção comum e fazer a junção ou comparação.

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

13

@Valkyrie awesome answer. Pensei em colocar aqui um caso ao executar o mesmo com uma subconsulta dentro de um procedimento armazenado, pois me perguntei se sua resposta funcionaria nesse caso e foi incrível.

...WHERE fieldname COLLATE DATABASE_DEFAULT in (
          SELECT DISTINCT otherfieldname COLLATE DATABASE_DEFAULT
          FROM ...
          WHERE ...
        )

12

No critério where, adicione collate SQL_Latin1_General_CP1_CI_AS

Isso funciona para mim.

WHERE U.Fullname = @SearchTerm  collate SQL_Latin1_General_CP1_CI_AS

6

A causa principal é que o banco de dados do servidor sql do qual você tirou o esquema possui um agrupamento diferente da instalação local. Se você não quiser se preocupar com o agrupamento, reinstale o SQL Server localmente usando o mesmo agrupamento do banco de dados do SQL Server 2008.


Teve o mesmo problema, primeiro você precisa verificar a propriedade do servidor e do banco de dados para ver se eles têm o mesmo agrupamento #
2416

5

erro (Não é possível resolver o conflito de agrupamento entre ....) geralmente ocorre ao comparar dados de vários bancos de dados.

como você não pode alterar o agrupamento de bancos de dados agora, use COLLATE DATABASE_DEFAULT.

----------
AND db1.tbl1.fiel1 COLLATE DATABASE_DEFAULT =db2.tbl2.field2 COLLATE DATABASE_DEFAULT 

isso não é diferente de outra resposta já fornecida: stackoverflow.com/a/1607725/479251
Pac0

4

Eu tive algo parecido com isso antes, e o que descobrimos foi que o agrupamento entre duas tabelas era diferente.

Verifique se são iguais.


4

Graças à resposta de marc_s, resolvi meu problema original - inspirado a dar um passo adiante e postar uma abordagem para transformar uma tabela inteira de cada vez - script tsql para gerar as instruções alter column:

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 Afiliado ALTER COLUMN myTable NVARCHAR (4000) COLLATE Latin1_General_CI_AS NOT NULL

Eu admito que estou intrigado com a necessidade de col.max_length / 2 -


Eu acho que a divisão por dois é necessária porque o comprimento é armazenado como o número de bytes internamente. Nvarchar usa dois bytes por caractere em vez de um como varchar.
Zebi

Bom trabalho, como o número de consultas de consulta acima acima conta para tipos de dados ncha provavelmente por causa de col.max_length / 2 -
Imran

2

Para aqueles que possuem um script CREATE DATABASE (como foi o meu caso) para o banco de dados que está causando esse problema, você pode usar o seguinte script CREATE para corresponder ao agrupamento:

-- 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

ou

-- 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

Isso aplica o agrupamento desejado a todas as tabelas, que era exatamente o que eu precisava. É ideal tentar manter o agrupamento igual para todos os bancos de dados em um servidor. Espero que isto ajude.

Mais informações no seguinte link: SQL SERVER - Criando banco de dados com agrupamento diferente no servidor


2

Eu usei o conteúdo deste site para criar o seguinte script que altera o agrupamento de todas as colunas em todas as tabelas:

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

11
SYSCOLUMNS.length das colunas nvarchar devem ser divididas por 2
palota

2

Verifique o nível de agrupamento incompatível (servidor, banco de dados, tabela, coluna, caractere).

Se for o servidor, essas etapas me ajudaram uma vez:

  1. Pare o servidor
  2. Encontre a ferramenta sqlservr.exe
  3. Execute este comando:

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

  4. Inicie seu servidor sql:

    net start name_of_instance

  5. Verifique o agrupamento do seu servidor novamente.

Aqui está mais informações:

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


2

Se isso ocorrer em todo o seu banco de dados, é melhor alterar o agrupamento do banco de dados da seguinte forma:

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 

Referência aqui


infelizmente isso não vai alterar o agrupamento de tabelas existentes, mas apenas o padrão para novas tabelas
RockScience

2

Código adicionado à resposta do @ JustSteve para lidar com as colunas varchar e 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)

2

Para resolver esse problema na consulta sem alterar nenhum banco de dados, você pode converter as expressões no outro lado do sinal "=" com

COLLATE SQL_Latin1_General_CP1_CI_AS

como sugerido aqui .


1

Ocorreu um erro semelhante (não é possível resolver o conflito de agrupamento entre "SQL_Latin1_General_CP1_CI_AS" e "SQL_Latin1_General_CP1250_CI_AS" na operação INTERSECT) quando usei o driver jdbc antigo.

Resolvi isso baixando o novo driver da Microsoft ou o projeto de código aberto jTDS .


1

Aqui está o que fizemos: em nossa situação, precisamos que uma consulta ad hoc seja executada usando uma restrição de data sob demanda, e a consulta é definida em uma tabela.

Nossa nova consulta precisa corresponder dados entre bancos de dados diferentes e incluir dados de ambos.

Parece que o COLLATION é diferente entre o banco de dados que importa dados do sistema iSeries / AS400 e nosso banco de dados de relatórios - isso pode ocorrer devido aos tipos de dados específicos (como acentos gregos nos nomes etc.).

Então, usamos a cláusula de junção abaixo:

...LEFT Outer join ImportDB..C4CTP C4 on C4.C4CTP COLLATE Latin1_General_CS_AS=CUS_Type COLLATE Latin1_General_CS_AS

1

Você pode fazer isso facilmente usando 4 etapas fáceis

  1. faça backup do seu banco de dados, apenas
  2. alterar agrupamento do banco de dados: clique com o botão direito do mouse no banco de dados, selecione propriedades, vá para as opções e altere o agrupamento para o agrupamento necessário.
  3. Gere um script para descartar e recriar todos os objetos do banco de dados: clique com o botão direito do mouse no banco de dados, selecione tarefas, selecione gerar script ... (certifique-se de selecionar Descartar e criar nas opções avançadas do assistente, também selecione Esquema e dados)
  4. Execute o script gerado acima

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 )

0

Você pode não ter nenhum problema de agrupamento no banco de dados, mas se você restaurou uma cópia do banco de dados de um backup em um servidor com um agrupamento diferente da origem e seu código está criando tabelas temporárias, essas tabelas temporárias herdariam o agrupamento de servidor e haveria conflitos com seu banco de dados.


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

0

Eu tinha um requisito semelhante; documentando minha abordagem aqui para qualquer pessoa com um cenário semelhante ...

Cenário

  • Eu tenho um banco de dados de uma instalação limpa com os agrupamentos corretos.
  • Eu tenho outro banco de dados que possui os agrupamentos incorretos.
  • Preciso atualizar o último para usar os agrupamentos definidos no primeiro.

Solução

Use a Comparação de esquema do SQL Server (do SQL Server Data Tools / Visual Studio) para comparar a origem (instalação limpa) com o destino (o banco de dados com agrupamento inválido).

No meu caso, comparei os dois DBs diretamente; embora você possa trabalhar através de um projeto para permitir que você ajuste manualmente as peças entre ...

  • Execute o Visual Studio
  • Crie um novo projeto de dados do SQL Server
  • Clique em Ferramentas, SQL Server, Nova comparação de esquema
  • Selecione o banco de dados de origem
  • Selecione o banco de dados de destino
  • Clique nas opções (⚙)
    • Em Object Typesselecione apenas os tipos nos quais você está interessado (para mim, era apenas Viewse Tables)
    • Em Generalselecionar:
      • Bloquear a possível perda de dados
      • Desativar e reativar gatilhos DDL
      • Ignorar caminho do arquivo do provedor criptográfico
      • Ignorar arquivo e caminho do arquivo de log
      • Ignorar tamanho do arquivo
      • Ignorar posicionamento do grupo de arquivos
      • Ignorar caminho do arquivo de catálogo de texto completo
      • Ignorar caixa de palavras-chave
      • Ignorar SIDs de login
      • Ignorar identificadores citados
      • Ignorar a duração da rota
      • Ignorar ponto e vírgula entre instruções
      • Ignorar espaço em branco
      • Módulo de atualização de script
      • Validação de script para novas restrições
      • Verifique a compatibilidade do agrupamento
      • Verificar implantação
  • Clique em Comparar
    • Desmarque todos os objetos sinalizados para exclusão (NB: eles ainda podem ter problemas de agrupamento; mas como eles não estão definidos no nosso db de origem / modelo, não sabemos; de qualquer forma, não queremos perder as coisas se estivermos segmentando apenas alterações de agrupamento). Você pode desmarcar tudo de uma vez clicando com o botão direito do mouse na DELETEpasta e selecionando EXCLUDE.
    • Da mesma forma, excluir qualquer CREATE objetos (aqui, como eles não existem no destino, eles não podem ter o agrupamento errado lá; se eles devem existir é uma questão para outro tópico).
    • Clique em cada objeto em ALTERAR para ver o script desse objeto. Use o diff para garantir que apenas alteremos o agrupamento (qualquer outra diferença detectada manualmente, você provavelmente desejará excluir / manipular esses objetos manualmente).
  • Clique Updatepara enviar alterações

Isso ainda envolve algum esforço manual (por exemplo, verificar se você está impactando apenas o agrupamento) - mas ele lida com dependências para você.

Além disso, você pode manter um projeto de banco de dados do esquema válido para poder usar um modelo universal para seus DBs caso tenha mais de 1 para atualizar, assumindo que todos os DBs de destino terminem com o mesmo esquema.

Você também pode usar localizar / substituir os arquivos em um projeto de banco de dados, caso deseje alterar as configurações em massa (por exemplo, para criar o projeto a partir do banco de dados inválido usando comparação de esquema, alterar os arquivos do projeto e, em seguida, alternar a origem / destino em o esquema é comparado para enviar suas alterações de volta ao banco de dados).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.