Eliminer ou chercher les accents

Une question qui m'a été posée : comment savoir si la colonne d'une table contient des caractères accentués ou des minuscules et comment y éliminer les accents ? Cela avec SQL comme avec SSIS : voyons quelques astuces...

Mon collègue Frédéric Brouard a écrit un article à ce sujet : http://mssqlserver.fr/eliminer-les-accents-dans-une-chaine-de-caracteres/

L'astuce est bonne : pour enlever les accents d'une chaîne de caractères, on peut la traduire dans dans un des classements (collation) qui n'incorporent pas de caractères accentués, comme le grec (CP1253) ou le cyrillique (CP1251). Cela évitera des fonctions UDF, telles qu'on en trouve, catastrophiques en performances, qui font du parsing et de multiples remplacements. Un simple UPDATE fera l'affaire et effectuera l'opération, en passant si nécessaire en majuscules au passage comme dans cet exemple :

CREATE TABLE T_Noms (Id INT IDENTITY, Nom VARCHAR(30))
INSERT T_Noms (Nom) VALUES ('AMELIE'),('Amélie'),('Amelie'),('amelie'),('AMÉLIE'),('àéèêïôöù'),('ÀÉÈÊÏÔÖÙ')
SELECT * FROM T_Noms
UPDATE T_Noms SET Nom = UPPER(Nom) COLLATE SQL_Latin1_General_CP1251_CS_AS
SELECT * FROM T_Noms

Cela fonctionne bien, mais si notre colonne à transformer est en unicode (NVARCHAR), une opération de transtypage sera à ajouter :

UPDATE T_Noms SET Nom = UPPER(CAST(Nom AS VARCHAR(30))) COLLATE SQL_Latin1_General_CP1251_CS_AS

Mais une des questions posées était de filtrer nos lignes (requête SELECT) sur les noms qui contiennent des des accents. Ici, l'appel à une sous-requête et une autojointure (self join) sera nécessaire, par exemple :

CREATE TABLE T_Noms (Id INT IDENTITY, Nom NVARCHAR(30))
INSERT T_Noms (Nom) VALUES (N'AMELIE'),(N'Amélie'),(N'Amelie'),(N'amelie'),(N'AMÉLIE'),(N'àéèêïôöù'),(N'ÀÉÈÊÏÔÖÙ')
SELECT * FROM T_Noms
-- filtrons
SELECT A.*
FROM T_Noms A
    JOIN (SELECT Id, Nom COLLATE SQL_Latin1_General_CP1251_CS_AS AS Nom FROM T_Noms) B
    ON A.Id = B.Id
 -- possède des accents
WHERE CAST(A.Nom AS VARCHAR(30)) <> CAST(B.Nom AS VARCHAR(30)) COLLATE French_CI_AS
-- possède des minuscules ou des accents
-- WHERE CAST(A.Nom AS VARCHAR(30)) <> UPPER(CAST(B.Nom AS VARCHAR(30))) COLLATE French_CS_AS  

Et pour retirer les accents dans un flux de données SSIS ?

On pourra utiliser la même astuce de pages de codes et éviter ainsi l'utilisation d'un script C# ou VB très lourd qui parse chaque caractère... Il suffira d'utiliser une colonne dérivée pour faire la transformation, avec la formule :

(DT_STR,30,1252)(DT_WSTR,30)(DT_STR,30,1251)Nom

ou pour de l'unicode

(DT_WSTR,30)(DT_STR,30,1251)Nom

Dernier point : pourquoi diantre supprimer les accents dans les noms ?

C'est dommage, car on perd définitivement une information !

A noter par ailleurs que s'il s'agit d'actes, de documents administratifs ou d'état civil, l'altération du nom est interdite par la loi (article 433-19 du code pénal).

Le motif évoqué pour supprimer les accents (et les minuscules !) dans une base de données était qu'une recherche d'un nom accentué ne fonctionnait pas facilement pour les utilisateurs. Pour résoudre ce problème, il y a pourtant beaucoup mieux : utiliser pour cette colonne de la table un classement (collation) insensible à la casse et aux accents...