Comment utiliser COLLATE
avec UNION
? Je veux réunir 2 tables (les deux ont les mêmes colonnes et les mêmes types: varchar,int, int, decimal
).
J'ai eu l'erreur suivante:
sg 468, niveau 16, état 9, ligne 1 Impossible de résoudre le conflit de classement entre "Serbian_Latin_100_CI_AS" et "Croatian_CI_AS" dans l'opération UNION.
Mon instruction SQL:
select * from #IA_BIH
union
select * from #IA_MNE
Où dois-je insérer collate database_default
? J'ai essayé différentes combinaisons, mais cela n'a pas fonctionné.
Sur la base des noms de classement, je suppose que vous utilisez Microsoft SQL Server.
COLLATE peut être utilisé au niveau de la base de données ou au niveau de la colonne. Dans la mesure où vous essayez d'UNIER deux tables, l'utilisation du classement des colonnes sur les colonnes nécessaires résoudra votre requête.
Voici un exemple de code pour vous aider:
use testdb
GO
CREATE TABLE dbo.Serbian (Name VARCHAR(20) COLLATE Serbian_Latin_100_CI_AS);
CREATE TABLE dbo.Croatian (Name VARCHAR(20) COLLATE Croatian_CI_AS);
GO
INSERT INTO dbo.Serbian VALUES ('serbian');
INSERT INTO dbo.Croatian VALUES ('croation');
GO
-- Collate to a particular named collation
SELECT Name COLLATE Serbian_Latin_100_CI_AS as CollatedNameSerbian from dbo.Serbian
UNION ALL
SELECT Name COLLATE Serbian_Latin_100_CI_AS from dbo.Croatian
GO
-- Collate to the database default collation
SELECT Name COLLATE database_default as CollatedNameDBDefault from dbo.Serbian
UNION ALL
SELECT Name COLLATE database_default from dbo.Croatian
GO
DROP TABLE dbo.Serbian;
DROP TABLE dbo.Croatian;
GO
Bien sûr, si vous avez plusieurs colonnes avec des classements conflictuels, vous devrez également définir leurs classements.
Les classements peuvent être un peu délicats, en particulier pour les données VARCHAR
. Pour les données NVARCHAR
et VARCHAR
, les classements contrôlent les règles de tri et de comparaison. Mais pour les données VARCHAR
, les classements contrôlent également le jeu de caractères (c'est-à-dire quelle page de code est utilisée pour déterminer quel caractère chaque valeur de 8 bits représente). Ainsi, la modification des classements sur les données VARCHAR
can entraîne une perte de données:
SELECT CHAR(230) AS [DB-Collation],
CHAR(230) COLLATE Korean_100_CI_AS AS [Korean],
CHAR(230) COLLATE Albanian_CI_AS AS [Albanian],
CHAR(230) COLLATE Greek_100_CI_AS AS [Greek];
-- æ a ?
Cependant, étant donné que vous avez une incompatibilité de classement, vous devez en modifier un. Je déconseille d'utiliser database_default
dans ce cas particulier, car cela sera relatif à la base de données à partir de laquelle la requête est exécutée, ce qui pourrait entraîner un comportement incohérent.
Heureusement, les deux classements mentionnés dans l'erreur ont la même page de codes: 1250. Vous pouvez trouver ces informations à l'aide de la requête suivante:
SELECT col.[name], COLLATIONPROPERTY(col.[name], 'CodePage') AS [CodePage]
FROM sys.fn_helpcollations() col
WHERE [name] IN (N'Serbian_Latin_100_CI_AS', N'Croatian_CI_AS');
À ce stade, vous devez choisir l'un de ces deux pour forcer l'autre à être le même. Étant donné que les deux classements utilisent la même page de codes, le choix n'affectera pas le jeu de caractères utilisé. La seule différence dont vous devez vous préoccuper est les règles de tri et de comparaison entre le serbe et le croate; choisissez celui qui correspond le mieux aux attentes des utilisateurs finaux.
Une option consiste à forcer le classement dans l'instruction SELECT
comme il semble que vous essayez de le faire, et comme indiqué dans la réponse de @ RLF. L'inconvénient ici est que vous ne pouvez plus utiliser SELECT *
(s'il s'agit de code dans une procédure stockée, il est probablement préférable de ne pas utiliser SELECT *
en tous cas).
Une autre option consiste à forcer le classement pour l'une de ces tables lorsque vous créez la table temporaire, que cela se fasse à l'aide de CREATE TABLE
ou SELECT INTO
:
SELECT ac.*
FROM sys.all_columns ac
WHERE ac.[object_id] = OBJECT_ID(N'sys.objects')
AND ac.[name] = N'name';
-- SQL_Latin1_General_CP1_CI_AS (on my system, at least)
SELECT [name] COLLATE Hebrew_100_CI_AS AS [name]
INTO #coltest
FROM sys.objects;
SELECT sc.*
FROM [tempdb].sys.columns sc
WHERE sc.[object_id] = OBJECT_ID(N'tempdb..#coltest');
-- Hebrew_100_CI_AS
Les avantages ici sont que vous pouvez alors:
SELECT *
dans votre requête UNION
.COLLATE
à chacune.Et, en supposant que le classement par défaut, pour la base de données dans laquelle CREATE TABLE
ou SELECT INTO
est en cours d'exécution, est l'un des deux classements indiqués dans le message d'erreur, alors vous pouvez continuer et utiliser COLLATE database_default
.