2 avr. 2013

[Snippet] Exécuter une requête SQL sans prise en compte des accents

Si vous essayez de faire une requête SQL qui utilise une colonne de votre table qui peut contenir des accents, mais vous souhaitez les résultats avec ou sans accents :

Il faut d'une part, lors de la création de votre requête, enlever tous les accents de la valeur recherchée.
D'autre part, il faut indiquer à la requête SQL de faire pareil pour les données de la table.
Note : Si la colonne concernée par la recherche est une clé primaire ou un index, alors le SGBD prend généralement en charge la recherche avec ou sans accents naturellement.

La requête va comparer, pour chaque ligne de la table, si la valeur de la ligne est égale à la valeur recherchée. Il faut donc que, pour chaque valeur, remplacer ses accents par des caractères non accentués.

Il est possible de faire des REPLACE() successifs, mais il y a une méthode bien plus pratique : TRANSLATE().
Attention : TRANSLATE() n'existe que pour certains SGBD, vous pouvez créer une fonction pour contourner le problème avec MySQL.
Voici le script de contournement :

# Changement du charset pour protéger CHAR_LENGTH
SET NAMES utf8;

DELIMITER //

# Création de la function translate

CREATE FUNCTION translate(V_string VARCHAR(255), V_from VARCHAR(255), V_to VARCHAR(255))
RETURNS VARCHAR(255) DETERMINISTIC
BEGIN
 DECLARE i INT;
 SET i = CHAR_LENGTH(V_from);

 WHILE i > 0 DO
  SET V_string = REPLACE(V_string, SUBSTR(V_from, i, 1), SUBSTR(V_to, i, 1));
  SET i = i - 1;
 END WHILE;

 RETURN V_string;
END
//

# Restauration du délimiteur d'origine
DELIMITER ;

Ce code est tiré et corrigé de cet article.

TRANSLATE va permettre de donner deux listes de caractères : chaque caractère (de la première liste) qui sera trouvé dans la valeur, sera remplacé par l'autre caractère (celui de la seconde liste situé à la même position).

Exemple :
TRANSLATE("coucou","u","i") // donnera coicoi.

Donc exemple plus intéressant :
TRANSLATE("Cédric","é","e") // donnera Cedric.

Exemple concret :
SELECT * FROM maTable WHERE TRANSLATE(prenom,'ÁÀÂÄÃÅÇÉÈÊËÍÏÎÌÑÓÒÔÖÕÚÙÛÜÝáàâäãåçéèêëíìîïñóòôöõúùûüýÿ', 'AAAAAACEEEEIIIINOOOOOUUUUYaaaaaaceeeeiiiinooooouuuuyy') = 'Cédric';


N'oubliez pas un petit LOWER (ou UPPER) pour ignorer la casse.