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, l'erreur est collée dans le titre après l'ajout des deux jointures de la table C. Je pense que cela peut avoir un lien 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.
Vous avez une incompatibilité de deux collations différentes dans votre table. Vous pouvez vérifier les classements de chaque colonne de votre table 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 de chaînes. Il est généralement judicieux d'utiliser un seul classement unique dans l'ensemble de votre base de données. N'utilisez pas différents classements au sein d'une même table ou base de données. Vous ne faites que poser problème.
Une fois que vous avez défini 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
UPDATE: pour trouver les index en texte intégral 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)
Je fais ce qui suit:
...WHERE
fieldname COLLATE DATABASE_DEFAULT = otherfieldname COLLATE DATABASE_DEFAULT
Fonctionne à chaque fois. :)
Utilisez la clause collate
dans votre requête:
LEFT JOIN C tO_C on tA.FieldName = 'CID' AND tA.oldValue COLLATE Latin1_General_CI_AS = tO_C.Name
La syntaxe n'est peut-être pas exacte (check BOL), mais vous pouvez le faire pour modifier le classement à la volée de 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 modifier - dans cet exemple, j'ai modifié le classement du champ tA.oldValue
.
Identifiez les champs pour lesquels cette erreur est générée et ajoutez 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
...
@Valkyrie réponse géniale. Je pensais avoir mis ici un cas lorsqu’il effectuait 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 ...
)
Dans les critères où ajoutez collate SQL_Latin1_General_CP1_CI_AS
Cela fonctionne pour moi.
WHERE U.Fullname = @SearchTerm collate SQL_Latin1_General_CP1_CI_AS
Cela peut facilement arriver lorsque vous avez 2 bases de données différentes et spécialement 2 bases de données différentes à partir de 2 serveurs différents. La meilleure option est de le 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
La cause première est que la base de données du serveur SQL dont vous avez pris le schéma a un classement différent de votre installation locale. Si vous ne souhaitez 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.
une erreur (impossible de résoudre le conflit de classement entre ....) se produit généralement lors de la comparaison de données provenant de plusieurs bases de données.
étant donné que 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
J'ai eu quelque chose comme ça avant, et ce que nous avons trouvé est que la collation entre 2 tables était différente
Vérifiez que ce sont les mêmes.
Grâce à la réponse de marc_s, j'ai résolu le problème initial - j'ai eu l'inspiration d'aller plus loin et de publier une approche pour transformer une table entière à la fois - le 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 PAS NULL
Je vais admettre que je suis perplexe devant la nécessité de col.max_length/2 -
J'ai utilisé le contenu de ce site pour créer le script suivant qui modifie le classement de toutes les colonnes de 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
Vérifiez le niveau de classement qui ne correspond pas (serveur, base de données, table, colonne, caractère).
Si c'est le serveur, ces étapes m'ont aidé une fois:
Exécutez cette commande:
sqlservr -m -T4022 -T3659 -s"name_of_insance"
-q "name_of_collation"
Démarrez votre serveur SQL:
net start name_of_instance
Vérifiez à nouveau le classement de votre serveur.
Voici plus d'infos:
https://www.mssqltips.com/sqlservertip/3519/changing-sql-server-collation-after-installation/
Si cela se produit dans l'ensemble de votre base de données, il est préférable de modifier le classement de votre 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
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 vous aidera.
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
Code ajouté à la réponse de @ JustSteve pour traiter 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)
Vous pouvez facilement le faire en utilisant 4 étapes faciles
voici ce que nous avons fait. Dans notre cas, nous avons besoin d’une requête ad hoc à exécuter à l’aide d’une restriction de date à la demande, et la requête est définie dans une table.
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 peut ê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
Pour résoudre ce problème dans la requête sans changer aucune des bases de données, vous pouvez transtyper les expressions de l’autre côté du signe "=" avec
COLLATE SQL_Latin1_General_CP1_CI_AS
comme suggéré ici .
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 le nouveau pilote à partir de Microsoft ou d'un projet open-source jTDS .
ALTER DATABASE test2 - mettez votre nom de base de données ici COLLATE Latin1_General_CS_AS - remplace par tout classement dont vous avez besoin
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 )
Vous ne rencontrez peut-être aucun problème de classement dans votre base de données, mais si vous restauriez une copie de votre base de données à partir d'une sauvegarde sur un serveur avec un classement différent de celui d'origine, et que votre code crée des tables temporaires, ces tables temporaires hériteraient du classement. le serveur et il y aurait des conflits avec votre base de données.