Impossible de résoudre le conflit de classement entre "SQL_Latin1_General_CP1_CI_AS" et "Latin1_General_CI_AS" dans l'opération égale à

345

J'ai le code suivant

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

Lors de l'exécution du code, je reçois l'erreur collée dans le titre après avoir ajouté les deux jointures pour le tableau C.Je pense que cela peut avoir quelque chose à voir avec le fait que j'utilise SQL Server 2008 et que j'ai restauré une copie de cette base de données sur ma machine qui est 2005.

jhowe
la source

Réponses:

307

Vous avez une incompatibilité de deux classements différents dans votre table. Vous pouvez vérifier les classements de chaque colonne de vos tables en utilisant cette requête:

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

Les classements sont nécessaires et utilisés lors de la commande et de la comparaison des chaînes. C'est généralement une bonne idée d'avoir un classement unique et unique utilisé dans toute votre base de données - n'utilisez pas de classements différents dans une seule table ou base de données - vous ne demandez que des problèmes ...

Une fois que vous avez choisi un seul classement, vous pouvez modifier les tables / colonnes qui ne correspondent pas encore à l'aide de cette commande:

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

Marc

MISE À JOUR: pour trouver les index fulltext dans votre base de données, utilisez cette requête ici:

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

Vous pouvez ensuite supprimer l'index de texte intégral en utilisant:

DROP FULLTEXT INDEX ON (tablename)
marc_s
la source
Merci marc, c'est exactement le type de chose que je cherchais, une des tables était un classement différent pour une raison stupide! Je vais essayer de modifier le classement standard et voir ce qui se passe.
jhowe
marc J'obtiens ceci maintenant: Impossible de modifier ou de supprimer la colonne car elle est activée pour la recherche en texte intégral.
jhowe
1
Dans ce cas, vous devrez supprimer temporairement votre index de texte intégral sur cette table, modifier le classement, puis recréer à nouveau l'index de texte intégral
marc_s
1
Merci OP, je mettais en place une table temporaire, cela a donc aidé, mais comme je ne pouvais pas modifier la table, je devais simplement la déclarer correctement pour commencer (comme suit): DECLARE @Table TABLE (CompareMessage VARCHAR (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL)
FrostbiteXIII
1
pourquoi ne pouvons-nous pas avoir 2 classements différents sur la même table. Si j'ai 1 colonne en tant que nvarchar qui n'a besoin que de noms anglais et d'une autre colonne en lettres russes, d'une autre colonne en lettres japonaises. Comment organiser cela? Existe-t-il un seul classement couvrant tout cela?
batmaci
856

Je fais ce qui suit:

...WHERE 
    fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT

Fonctionne à chaque fois. :)

Valkyrie
la source
68
Ceci est l'un des messages les plus utiles sur SO
Jamie Strauss
2
J'ai utilisé cette solution parce que je travaillais avec deux systèmes hérités utilisant la même base de données, donc je ne savais pas si la modification du classement des tables romprait la fonctionnalité.
paolobueno
5
Si les deux mêmes champs sont utilisés ensemble à d'autres endroits (comparaisons, unions, fusion, etc ...) assurez-vous que chacun d'eux a également le classement spécifié.
Zarepheth
5
C'est extrêmement utile. J'utilise une base de données locale et j'interroge un serveur lié et ils ont deux classements différents. Évidemment, je ne peux pas changer le classement sur le serveur lié, et je ne voulais pas changer le mien localement, c'est donc absolument la meilleure réponse.
2014
7
@ppumkin Bien que ce soit une excellente solution, elle évite toujours le problème, plutôt que de le résoudre. Sauf si vous souhaitez modifier le classement de chaque requête, ce qui est fastidieux et ne fonctionne pas de manière optimale. Bien que ce soit une excellente réponse, la réponse acceptée, je pense, est la meilleure.
Rob
80

Utilisez la collateclause dans votre requête:

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

Je n'ai peut-être pas la syntaxe exacte (vérifiez BOL), mais vous pouvez le faire pour modifier le classement à la volée pour la requête - vous devrez peut-être ajouter la clause pour chaque jointure.

edit: J'ai réalisé que ce n'était pas tout à fait correct - la clause collate va après le champ que vous devez changer - dans cet exemple, j'ai changé le classement sur le tA.oldValuechamp.

Rayon
la source
29

Identifiez les champs pour lesquels il génère cette erreur et ajoutez-leur ce qui suit: COLLATE DATABASE_DEFAULT

Il y a deux tables jointes sur le champ Code:

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

Mettez à jour votre requête pour:

...
and table1.Code COLLATE DATABASE_DEFAULT = table2.Code COLLATE DATABASE_DEFAULT
...
Palak.Maheria
la source
Merci. Lorsque nous travaillons dans une base de données prod, nous ne pouvons pas toujours changer la structure de la base de données comme suggéré par la réponse acceptée.
Jennifer Wood
21

Cela peut facilement se produire lorsque vous avez 2 bases de données différentes et spécialement 2 bases de données différentes de 2 serveurs différents. La meilleure option est de la changer en une collection commune et de faire la jointure ou la comparaison.

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

@Valkyrie réponse géniale. Je pensais que je mettais ici un cas lors de l'exécution de la même chose avec une sous-requête à l'intérieur d'une procédure stockée, car je me demandais si votre réponse fonctionnait dans ce cas, et c'était génial.

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

Dans où les critères s'ajoutent collate SQL_Latin1_General_CP1_CI_AS

Cela fonctionne pour moi.

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

La cause principale est que la base de données du serveur SQL à partir de laquelle vous avez pris le schéma a un classement qui diffère de votre installation locale. Si vous ne voulez pas vous soucier du classement, réinstallez SQL Server localement en utilisant le même classement que la base de données SQL Server 2008.

Robert
la source
Eu le même problème, vous devez d'abord vérifier votre serveur et la propriété de la base de données pour voir s'ils ont le même classement
madan
5

erreur (ne peut pas résoudre le conflit de classement entre ....) se produit généralement lors de la comparaison des données de plusieurs bases de données.

puisque vous ne pouvez pas modifier le classement des bases de données maintenant, utilisez COLLATE DATABASE_DEFAULT.

----------
AND db1.tbl1.fiel1 COLLATE DATABASE_DEFAULT =db2.tbl2.field2 COLLATE DATABASE_DEFAULT 
chaminda welgamage
la source
ce n'est pas différent d'une autre réponse déjà donnée: stackoverflow.com/a/1607725/479251
Pac0
4

J'ai déjà eu quelque chose comme ça auparavant, et ce que nous avons constaté, c'est que le classement entre 2 tables était différent.

Vérifiez que ce sont les mêmes.

Adriaan Stander
la source
4

Grâce à la réponse de marc_s, j'ai résolu mon problème d'origine - inspiré pour aller plus loin et publier une approche pour transformer une table entière à la fois - script tsql pour générer les instructions 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)

obtient: ALTER TABLE Affilié ALTER COLUMN myTable NVARCHAR (4000) COLLATE Latin1_General_CI_AS NOT NULL

J'avoue être perplexe devant la nécessité de col.max_length / 2 -

justSteve
la source
Je pense que la division par deux est nécessaire car la longueur est stockée en tant que nombre d'octets en interne. Nvarchar prend deux octets par caractère au lieu d'un comme varchar.
Zebi
Excellent travail, mais le nombre de dosages de requêtes ci-dessus pour les types de données ncha est probablement dû à col.max_length / 2 -
Imran
2

Pour ceux qui ont un script CREATE DATABASE (comme c'était mon cas) pour la base de données à l'origine de ce problème, vous pouvez utiliser le script CREATE suivant pour faire correspondre le classement:

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

Cela applique le classement souhaité à toutes les tables, ce qui était exactement ce dont j'avais besoin. Il est idéal d'essayer de conserver le même classement pour toutes les bases de données sur un serveur. J'espère que cela t'aides.

Plus d'informations sur le lien suivant: SQL SERVER - Création d'une base de données avec un classement différent sur le serveur

pechar
la source
2

J'ai utilisé le contenu de ce site pour créer le script suivant qui modifie le classement de toutes les colonnes dans toutes les tables:

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
la source
1
SYSCOLUMNS.length des colonnes nvarchar doit être divisé par 2
palota
2

Vérifiez le niveau de classement qui ne correspond pas (serveur, base de données, table, colonne, caractère).

S'il s'agit du serveur, ces étapes m'ont aidé une fois:

  1. Arrêtez le serveur
  2. Trouvez votre outil sqlservr.exe
  3. Exécutez cette commande:

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

  4. Démarrez votre serveur SQL:

    net start name_of_instance

  5. Vérifiez à nouveau le classement de votre serveur.

Voici plus d'informations:

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

WholeLifeLearner
la source
2

Si cela se produit sur l'ensemble de votre base de données, il est préférable de modifier votre classement de base de données comme suit:

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 

Référence ici

Justin
la source
malheureusement, cela ne changera pas le classement des tables existantes, mais uniquement la valeur par défaut pour les nouvelles tables
RockScience
2

Ajout de code à la réponse de @ JustSteve pour gérer les colonnes varchar et 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
la source
2

Pour résoudre ce problème dans la requête sans modifier l'une des bases de données, vous pouvez convertir les expressions de l'autre côté du signe "=" avec

COLLATE SQL_Latin1_General_CP1_CI_AS

comme suggéré ici .

Lars Ericson
la source
1

J'ai eu une erreur similaire (Impossible de résoudre le conflit de classement entre "SQL_Latin1_General_CP1_CI_AS" et "SQL_Latin1_General_CP1250_CI_AS" dans l'opération INTERSECT), lorsque j'ai utilisé l'ancien pilote jdbc.

J'ai résolu ce problème en téléchargeant un nouveau pilote à partir de Microsoft ou du projet open-source jTDS .

krzy-wa
la source
1

voici ce que nous avons fait, dans notre situation, nous avons besoin d'une requête ad hoc à exécuter en utilisant une restriction de date sur demande, et la requête est définie dans un tableau.

Notre nouvelle requête doit faire correspondre les données entre différentes bases de données et inclure les données des deux.

Il semble que la COLLATION soit différente entre la base de données qui importe les données du système iSeries / AS400 et notre base de données de rapports - cela pourrait être dû aux types de données spécifiques (tels que les accents grecs sur les noms, etc.).

Nous avons donc utilisé la clause de jointure ci-dessous:

...LEFT Outer join ImportDB..C4CTP C4 on C4.C4CTP COLLATE Latin1_General_CS_AS=CUS_Type COLLATE Latin1_General_CS_AS
Notre homme en banane
la source
1

Vous pouvez facilement le faire en utilisant 4 étapes faciles

  1. sauvegarder votre base de données, au cas où
  2. modifier le classement de la base de données: cliquez avec le bouton droit sur la base de données, sélectionnez les propriétés, accédez aux options et modifiez le classement en le classement requis.
  3. Générez un script pour supprimer et recréer tous vos objets de base de données: cliquez avec le bouton droit sur votre base de données, sélectionnez des tâches, sélectionnez générer un script ... (assurez-vous de sélectionner Supprimer et créer dans les options avancées de l'Assistant, sélectionnez également Schéma et données)
  4. Exécutez le script généré ci-dessus
Felix Mwiti Mugambi
la source
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
la source
0

Vous ne pouvez avoir aucun problème de classement dans votre base de données, mais si vous avez restauré une copie de votre base de données à partir d'une sauvegarde sur un serveur avec un classement différent de l'origine, et que votre code crée des tables temporaires, ces tables temporaires hériteraient du classement de le serveur et il y aurait des conflits avec votre base de données.

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

J'avais une exigence similaire; documenter mon approche ici pour toute personne ayant un scénario similaire ...

Scénario

  • J'ai une base de données d'une installation propre avec les classements corrects.
  • J'ai une autre base de données qui a les mauvais classements.
  • J'ai besoin de mettre à jour ce dernier pour utiliser les classements définis sur le premier.

Solution

Utilisez la comparaison de schémas SQL Server (à partir de SQL Server Data Tools / Visual Studio) pour comparer la source (installation propre) avec la destination (la base de données avec un classement non valide).

Dans mon cas, j'ai comparé les deux DB directement; bien que vous puissiez travailler via un projet pour vous permettre de modifier manuellement les pièces entre les deux ...

  • Exécutez Visual Studio
  • Créer un nouveau projet de données SQL Server
  • Cliquez sur Outils, SQL Server, Comparaison de nouveaux schémas
  • Sélectionnez la base de données source
  • Sélectionnez la base de données cible
  • Cliquez sur les options (⚙)
    • Sous Object Typessélectionnez uniquement les types qui vous intéressent (pour moi, c'était seulement ViewsetTables )
    • Sous General sélectionner:
      • Bloquer la perte éventuelle de données
      • Désactiver et réactiver les déclencheurs DDL
      • Ignorer le chemin d'accès au fichier du fournisseur de chiffrement
      • Ignorer le chemin du fichier et du fichier journal
      • Ignorer la taille du fichier
      • Ignorer le placement des groupes de fichiers
      • Ignorer le chemin du fichier de catalogue de texte intégral
      • Ignorer la casse des mots clés
      • Ignorer les SID de connexion
      • Ignorer les identificateurs entre guillemets
      • Ignorer la durée de vie de l'itinéraire
      • Ignorer le point-virgule entre les instructions
      • Ignorer les espaces
      • Module d'actualisation de script
      • Validation de script pour les nouvelles contraintes
      • Vérifier la compatibilité du classement
      • Vérifier le déploiement
  • Cliquez sur Comparer
    • Décochez tous les objets marqués pour suppression (NB: ceux-ci peuvent toujours avoir des problèmes de classement; mais comme ils ne sont pas définis dans notre base de données / modèle, nous ne le savons pas; de toute façon, nous ne voulons pas perdre des choses si nous sommes ciblant uniquement les modifications de classement). Vous pouvez décocher tout d'un coup en cliquant avec le bouton droit sur le DELETEdossier et en le sélectionnant EXCLUDE.
    • Exclure également pour tout CREATE objets (ici, car ils n'existent pas dans la cible, ils ne peuvent pas y avoir le mauvais classement; s'ils doivent exister est une question pour un autre sujet).
    • Cliquez sur chaque objet sous MODIFIER pour voir le script de cet objet. Utilisez le diff pour vous assurer que nous ne modifions que le classement (toute autre différence détectée manuellement, vous voudrez probablement exclure / gérer ces objets manuellement).
  • Cliquez Updatepour pousser les changements

Cela implique toujours un effort manuel (par exemple, vérifier que vous n'affectez que le classement) - mais il gère les dépendances pour vous.

Vous pouvez également conserver un projet de base de données du schéma valide afin que vous puissiez utiliser un modèle universel pour vos bases de données si vous avez plus de 1 à mettre à jour, en supposant que toutes les bases de données cibles doivent se retrouver avec le même schéma.

Vous pouvez également utiliser la fonction de recherche / remplacement sur les fichiers d'un projet de base de données si vous souhaitez y modifier en masse les paramètres (par exemple, pour pouvoir créer le projet à partir de la base de données non valide à l'aide de la comparaison de schémas, modifier les fichiers du projet, puis basculer la source / cible dans comparer le schéma pour renvoyer vos modifications à la base de données).

JohnLBevan
la source