Impossibile risolvere il conflitto di regole di confronto tra "SQL_Latin1_General_CP1_CI_AS" e "Latin1_General_CI_AS" nell'operazione uguale


345

Ho il codice seguente

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

Quando eseguo il codice, ricevo l'errore incollato nel titolo dopo aver aggiunto i due join per la tabella C. Penso che questo potrebbe avere qualcosa a che fare con il fatto che sto usando SQL Server 2008 e ho ripristinato una copia di questo db su la mia macchina che è il 2005.

Risposte:


307

Hai una mancata corrispondenza di due diverse regole di confronto nel tuo tavolo. Puoi controllare quali regole di confronto hanno ciascuna colonna nelle tue tabelle usando questa query:

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

Le collation sono necessarie e utilizzate per ordinare e confrontare le stringhe. In genere è una buona idea utilizzare una raccolta unica e unica in tutto il database - non utilizzare regole di confronto diverse all'interno di una singola tabella o database - stai solo chiedendo problemi ....

Una volta stabilito un singolo confronto, puoi modificare quelle tabelle / colonne che non corrispondono ancora usando questo comando:

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

Marc

AGGIORNAMENTO: per trovare gli indici full-text nel database, utilizzare questa query qui:

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

È quindi possibile eliminare l'indice full-text utilizzando:

DROP FULLTEXT INDEX ON (tablename)

Grazie a Marc che è esattamente il tipo di cosa che stavo cercando, uno dei tavoli era diverso per qualche stupida ragione! Proverò a modificare le regole di confronto standard e vedrò cosa succede.
jhowe,

marc lo sto ricevendo ora: impossibile modificare o eliminare la colonna perché è abilitato per la ricerca full-text.
jhowe,

1
In tal caso, dovrai rilasciare temporaneamente l'indice
full

1
Grazie OP, stavo configurando una tabella temporanea, quindi mi è stato di aiuto, ma poiché non potevo modificare la tabella, dovevo semplicemente dichiararla correttamente per iniziare (come segue): DECLARE @Table TABLE (CompareMessage VARCHAR (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)
FrostbiteXIII

1
perché non possiamo avere 2 diverse regole di confronto sullo stesso tavolo. Se ho 1 colonna come nvarchar che richiede solo nomi inglesi e altre colonne come lettere russe, altre colonne come lettere giapponesi. Come lo organizzo? Esiste un'unica raccolta che copre tutte queste?
Batmaci,

856

Faccio quanto segue:

...WHERE 
    fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT

Funziona ogni volta. :)


68
Questo è uno dei post più utili su SO
Jamie Strauss il

2
Ho usato questa soluzione perché stavo lavorando con due sistemi legacy usando lo stesso db, quindi non ero sicuro che la modifica delle regole di confronto delle tabelle avrebbe interrotto la funzionalità.
paolobueno,

5
Se gli stessi due campi vengono utilizzati insieme in altri luoghi (confronti, sindacati, coalizione, ecc ...), assicurarsi che ciascuno di questi abbia anche le regole di confronto specificate.
Zarepheth,

5
Questo è estremamente utile. Sto utilizzando un database locale e eseguo query su un server collegato e hanno due regole di confronto diverse. Ovviamente non posso cambiare le regole di confronto sul server collegato e non volevo cambiare il mio localmente, quindi questa è assolutamente la risposta migliore.
jtate

7
@ppumkin Sebbene sia un'ottima soluzione, evita ancora solo il problema, piuttosto che risolverlo. A meno che non si desideri modificare le regole di confronto per ogni query, che è noioso e non offre prestazioni ottimali. Sebbene sia un'ottima risposta, la risposta accettata che ritengo migliore.
Rob

80

Usa la collateclausola nella tua query:

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

Potrei non avere la sintassi esattamente corretta (controlla BOL), ma puoi farlo per cambiare le regole di confronto al volo per la query - potresti dover aggiungere la clausola per ogni join.

modifica: ho capito che non era del tutto corretto - la clausola di fascicolazione va dopo il campo che devi modificare - in questo esempio ho cambiato la fascicolazione sul tA.oldValuecampo.


29

Identifica i campi per i quali genera questo errore e aggiungi i seguenti: COLLATE DATABASE_DEFAULT

Esistono due tabelle unite nel campo Codice:

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

Aggiorna la tua query a:

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

Grazie. Quando si lavora in un database prod non possiamo sempre cambiare la struttura del database come suggerito dalla risposta accettata.
Jennifer Wood,

21

Ciò può accadere facilmente quando si dispone di 2 database diversi e in particolare 2 database diversi da 2 server diversi. La migliore opzione è quella di cambiarlo in una raccolta comune ed eseguire l'unione o il confronto.

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

13

@Valkyrie risposta fantastica. Ho pensato di inserire un caso quando eseguivo lo stesso con una subquery all'interno di una procedura memorizzata, poiché mi chiedevo se la tua risposta funzionasse in questo caso, ed è stato fantastico.

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

12

Nel punto in cui aggiungere i criteri collate SQL_Latin1_General_CP1_CI_AS

Questo funziona per me.

WHERE U.Fullname = @SearchTerm  collate SQL_Latin1_General_CP1_CI_AS

6

La causa principale è che il database del server sql da cui hai preso lo schema ha regole di confronto diverse dall'installazione locale. Se non si desidera preoccuparsi delle regole di confronto, reinstallare SQL Server localmente utilizzando le stesse regole di confronto del database SQL Server 2008.


Aveva lo stesso problema, devi prima controllare le proprietà del tuo server e database per vedere se hanno le stesse regole di confronto
madan

5

errore (Impossibile risolvere il conflitto di confronto tra ....) di solito si verifica durante il confronto dei dati da più database.

poiché non è possibile modificare le regole di confronto dei database ora, utilizzare COLLATE DATABASE_DEFAULT.

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

questo non è diverso da un altro già dato risposta: stackoverflow.com/a/1607725/479251
Pac0

4

Ho avuto qualcosa di simile prima e quello che abbiamo scoperto è che le regole di confronto tra 2 tavoli erano diverse.

Verifica che siano uguali.


4

Grazie alla risposta di marc_s ho risolto il mio problema originale - ispirato a fare un ulteriore passo avanti e pubblicare un approccio per trasformare un'intera tabella alla volta - tsql script per generare le istruzioni 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)

ottiene: ALTER TABLE Affiliato ALTER COLUMN myTable NVARCHAR (4000) COLLATE Latin1_General_CI_AS NOT NULL

Devo ammettere di essere perplesso dalla necessità di col.max_length / 2 -


Penso che la divisione per due sia necessaria perché la lunghezza è memorizzata come numero di byte internamente. Nvarchar prende due byte per carattere invece di uno come varchar.
Zebi,

Ottimo lavoro, quanto sopra conta il conteggio delle query per i tipi di dati ncha probabilmente a causa di col.max_length / 2 -
Imran

2

Per coloro che hanno uno script CREATE DATABASE (come nel mio caso) per il database che sta causando questo problema, è possibile utilizzare il seguente script CREATE per abbinare le regole di confronto:

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

Questo applica le regole di confronto desiderate a tutti i tavoli, che era proprio quello di cui avevo bisogno. È ideale per provare a mantenere le regole di confronto uguali per tutti i database su un server. Spero che questo ti aiuti.

Maggiori informazioni sul seguente collegamento: SERVER SQL : creazione di database con regole di confronto diverse sul server


2

Ho usato il contenuto di questo sito per creare il seguente script che modifica le regole di confronto di tutte le colonne in tutte le tabelle:

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

1
SYSCOLUMNS.lunghezza delle colonne nvarchar deve essere divisa per 2
palota

2

Controllare il livello di confronto non corrispondente (server, database, tabella, colonna, carattere).

Se è il server, questi passaggi mi hanno aiutato una volta:

  1. Ferma il server
  2. Trova il tuo strumento sqlservr.exe
  3. Esegui questo comando:

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

  4. Avvia il tuo server sql:

    net start name_of_instance

  5. Controlla di nuovo le regole di confronto del tuo server.

Ecco maggiori informazioni:

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


2

Se ciò si verifica in tutto il tuo DB, è meglio modificare le regole di confronto del DB in questo modo:

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 

Riferimento qui


sfortunatamente questo non cambierà le regole di confronto per le tabelle esistenti, ma solo l'impostazione predefinita per le nuove tabelle
RockScience

2

Aggiunto codice alla risposta di @ JustSteve per gestire le colonne 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

Per risolvere questo problema nella query senza modificare nessuno dei database, è possibile eseguire il cast delle espressioni sull'altro lato del segno "=" con

COLLATE SQL_Latin1_General_CP1_CI_AS

come suggerito qui .


1

Ho riscontrato un errore simile (Impossibile risolvere il conflitto di regole di confronto tra "SQL_Latin1_General_CP1_CI_AS" e "SQL_Latin1_General_CP1250_CI_AS" nell'operazione INTERSECT), quando ho utilizzato il vecchio driver jdbc.

Ho risolto questo problema scaricando un nuovo driver da Microsoft o dal progetto open source jTDS .


1

ecco cosa abbiamo fatto, nella nostra situazione abbiamo bisogno di una query ad hoc da eseguire usando una limitazione della data su richiesta, e la query è definita in una tabella.

La nostra nuova query deve abbinare i dati tra database diversi e includere i dati di entrambi.

Sembra che la COLLEZIONE sia diversa tra il db che importa i dati dal sistema iSeries / AS400 e il nostro database di report - questo potrebbe essere dovuto ai tipi di dati specifici (come accenti greci sui nomi e così via).

Quindi abbiamo usato la clausola join di seguito:

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

1

Puoi farlo facilmente usando 4 semplici passaggi

  1. eseguire il backup del database, in caso di necessità
  2. modifica delle regole di confronto del database: fare clic con il pulsante destro del mouse sul database, selezionare le proprietà, accedere alle opzioni e modificare le regole di confronto nella modalità di confronto richiesta.
  3. Genera uno script per eliminare e ricreare tutti gli oggetti del database: fai clic con il pulsante destro del mouse sul database, seleziona le attività, seleziona genera script ... (assicurati di selezionare Elimina e crea nelle Opzioni avanzate della procedura guidata, Seleziona anche Schema e dati)
  4. Esegui lo script generato sopra

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

Potresti non avere alcun problema di confronto nel tuo database, ma se hai ripristinato una copia del tuo database da un backup su un server con un confronto diverso dall'origine e il tuo codice crea tabelle temporanee, quelle tabelle temporanee erediteranno le regole di confronto da il server e ci sarebbero conflitti con il tuo database.


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

0

Avevo un requisito simile; documentando il mio approccio qui per chiunque abbia uno scenario simile ...

Scenario

  • Ho un database da un'installazione pulita con le regole di confronto corrette.
  • Ho un altro database che ha le regole di confronto errate.
  • Devo aggiornare quest'ultimo per utilizzare le regole di confronto definite nel primo.

Soluzione

Utilizzare Confronto schema di SQL Server (da SQL Server Data Tools / Visual Studio) per confrontare l'origine (installazione pulita) con la destinazione (il db con regole di confronto non valide).

Nel mio caso ho confrontato direttamente i due DB; sebbene tu possa lavorare tramite un progetto per permetterti di modificare manualmente i pezzi tra ...

  • Esegui Visual Studio
  • Creare un nuovo progetto dati SQL Server
  • Fare clic su Strumenti, SQL Server, Confronto nuovo schema
  • Seleziona il database di origine
  • Seleziona il database di destinazione
  • Fai clic sulle opzioni (⚙)
    • Sotto Object Typesseleziona solo i tipi che ti interessano (per me era solo Viewse Tables)
    • Sotto General selezionare:
      • Blocco sulla possibile perdita di dati
      • Disabilita e riattiva i trigger DDL
      • Ignora il percorso del file del provider crittografico
      • Ignora percorso file e registro
      • Ignora le dimensioni del file
      • Ignora il posizionamento del filegroup
      • Ignora il percorso del file del catalogo full-text
      • Ignora involucro delle parole chiave
      • Ignora i SID di accesso
      • Ignora identificatori tra virgolette
      • Ignora la durata del percorso
      • Ignora il punto e virgola tra le istruzioni
      • Ignora spazi bianchi
      • Modulo di aggiornamento degli script
      • Convalida dello script per nuovi vincoli
      • Verifica la compatibilità delle regole di confronto
      • Verifica la distribuzione
  • Fai clic su Confronta
    • Deseleziona tutti gli oggetti contrassegnati per l'eliminazione (NB: quelli potrebbero avere ancora problemi di confronto; ma poiché non sono definiti nel nostro db sorgente / modello non lo sappiamo; in entrambi i casi, non vogliamo perdere cose se stiamo indirizzato solo alle modifiche delle regole di confronto). Puoi deselezionare tutto in una volta facendo clic destro sulla DELETEcartella e selezionando EXCLUDE.
    • Allo stesso modo escludere per qualsiasi CREATE oggetto (qui poiché non esistono nella destinazione non possono avere lì regole di confronto errate; se dovrebbero esistere è una domanda per un altro argomento).
    • Fare clic su ciascun oggetto in MODIFICA per visualizzare lo script per quell'oggetto. Usa il diff per assicurarci che stiamo solo cambiando le regole di confronto (qualsiasi altra differenza rilevata manualmente probabilmente vorrai escludere / gestire quegli oggetti manualmente).
  • Fai clic Updateper inviare le modifiche

Ciò comporta comunque un certo sforzo manuale (ad esempio, verifica che stai solo influenzando le regole di confronto), ma gestisce le dipendenze per te.

Inoltre, è possibile mantenere un progetto di database dello schema valido in modo da poter utilizzare un modello universale per i propri DB se si dispone di più di 1 da aggiornare, presupponendo che tutti i DB di destinazione debbano finire con lo stesso schema.

È inoltre possibile utilizzare trova / sostituisci sui file in un progetto di database se si desidera modificare le impostazioni di massa lì (ad es. In modo da poter creare il progetto dal database non valido utilizzando il confronto dello schema, modificare i file di progetto, quindi attivare l'origine / destinazione in lo schema confronta per riportare le modifiche al DB).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.