Remplacer les caractères spéciaux d'une colonne par un espace

10

J'essaie d'écrire une requête qui remplace les caractères spéciaux par de l'espace. Le code ci-dessous permet d'identifier les lignes. (les caractères alphanumériques, la virgule et l'espace sont valides):

SELECT columnA
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'

Comment puis-je intégrer la fonction replace dans l'instruction select afin que tous les caractères autres que alphanumériques, virgule et espace dans le jeu de résultats soient remplacés par '' (espace). Celui-ci ne fonctionnera pas:

SELECT replace(columnA,'%[^a-Z0-9, ]%',' ')
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'
Stackoverflowuser
la source

Réponses:

11

Si vous êtes assuré de n'utiliser que les 26 lettres de l'alphabet anglais américain (versions majuscules et minuscules), alors vous pouvez vous en sortir en utilisant LIKEet / ou en PATINDEXutilisant la notation de plage simple de [a-z](vous ne le feriez pas besoin d'utiliser un "Z" majuscule lors de l'utilisation d'un classement insensible à la casse).

Mais, si vous pouvez obtenir des caractères non trouvés dans l'en-US alphabet encore disponibles dans diverses pages de codes / classements pour les VARCHARdonnées (par exemple Þ= capitale latine « Thorn » = SELECT CHAR(0xDE)), alors vous pourriez avoir besoin d'inclure ceux de la classe de caractères: [a-z0-9, Þ]. Bien sûr, ce que ces caractères supplémentaires seraient sur une base par page de codes.

Sachez également que le type de classement (SQL Server vs Windows) et les paramètres de sensibilité (casse, accent, etc. sensible vs insensible) affecteront les caractères inclus dans une plage particulière. Par exemple, les classements SQL Server trient les lettres majuscules et minuscules dans l'ordre opposé aux classements Windows. Autrement dit, en supposant un classement sensible à la casse pour les deux types de classement, l'un fera l'affaire AaBb...et l'autre le fera aAbB.... L'effet sera celui aqui sera dans la plage de l' A-Zun, mais pas de l'autre. Et la plage de a-Zne correspondra à aucun caractère dans un classement binaire (l'un se terminant par _BINou _BIN2, mais n'utilisez pas _BIN) étant donné que la valeur de Aest 65 etaest 97, il s'agit donc d'une plage non valide de 97 à 65 ;-). Il y a beaucoup trop de variations pour donner des exemples ici, donc j'essaierai de publier une explication détaillée sur mon blog très bientôt (puis je mettrai à jour cela avec le lien). Cependant, si vous allez être strict en acceptant uniquement les caractères anglais américain (même si vous pouvez obtenir des lettres valides dans d'autres langues), votre meilleure option sera probablement d'utiliser le modèle et le classement suivants:

LIKE '%[^A-Za-z0-9, ]%' COLLATE Latin1_General_100_BIN2

Maintenant, si vous prenez en charge des NVARCHARdonnées et pouvez obtenir des caractères "word" dans différentes langues, alors T-SQL ne sera pas d'une grande utilité car il n'a aucun moyen réel de différencier ces choses. Dans ce cas, vous devez utiliser une expression régulière (RegEx) - en particulier la Replaceméthode / fonction - et celles-ci ne sont disponibles que via SQLCLR. Ce qui suit montre un exemple de remplacement de plusieurs caractères "spéciaux", tout en laissant toutes les lettres valides dans au moins une langue:

DECLARE @Test NVARCHAR(500);
SET @Test = N'this$is%a<>TEST,;to}⌡↕strip╞╟╚══¶out_ç_ƒ▀ special-ij-೫-chars-舛-დ-א-B';
SELECT SQL#.RegEx_Replace4k(@Test, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL); 

Retour:

this is a  TEST, to   strip      out ç ƒ  special ij ೫ chars 舛 დ א B

L'expression RegEx signifie:

  • \W= un "échappement" RegEx signifiant "tout caractère autre qu'un mot"
  • \p{Pc}= une "catégorie" Unicode de "Ponctuation, connecteur" (nécessaire uniquement pour la correspondance car cette "catégorie" est spécifiquement exclue par l' \Wéchappement)
  • -[,]= soustraction de classe (ceci est nécessaire pour exclure les virgules de la correspondance comme "spéciale" car elles sont incluses dans l' \Wéchappement)

Vous pouvez faire une mise à jour d'une table simplement en émettant:

UPDATE tbl
SET    tbl.field = SQL#.RegEx_Replace4k(tbl.field, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL)
FROM   tbl
WHERE  SQL#.RegEx_IsMatch4k(tbl.field, N'[\W\p{Pc}-[,]]', 1, NULL) = 1;

Veuillez noter que pour ces exemples, j'ai utilisé deux fonctions disponibles dans la bibliothèque Free version SQL # des fonctions SQLCLR, que j'ai créée (mais encore une fois, elles sont gratuites). Notez également que j'ai utilisé les versions "4k" qui sont plus rapides en raison de l'utilisation NVARCHAR(4000)au lieu des NVARCHAR(MAX)types de paramètres. Si vos données utilisent NVARCHAR(MAX), supprimez simplement le "4k" des noms de fonction.

Veuillez également consulter:

Solomon Rutzky
la source
5

J'ai un article ici qui fait quelque chose de similaire .

Fondamentalement, j'utilise un CTE récursif pour aller en boucle encore et encore en remplaçant un "mauvais" caractère à la fois. J'utilise STUFF pour supprimer 1 caractère (bien que vous puissiez l'utiliser pour le remplacer par un espace) et PATINDEX pour trouver l'emplacement du caractère que je souhaite supprimer. Vous pouvez le modifier légèrement pour faire ce que vous cherchez. Cependant, il crée une "bonne" liste, il ne met pas à jour la liste existante.

DECLARE @Pattern varchar(50) = '%[^A-Za-z0-9, ]%';

WITH FixBadChars AS (SELECT StringToFix, StringToFix AS FixedString, 1 AS MyCounter, Id
                FROM BadStringList
                UNION ALL
                SELECT StringToFix, Stuff(FixedString, PatIndex(@Pattern, 
                    FixedString COLLATE Latin1_General_BIN2), 1, ' ') AS FixedString, 
                    MyCounter + 1, Id
                FROM FixBadChars
                WHERE FixedString COLLATE Latin1_General_BIN2 LIKE @Pattern)
SELECT StringToFix, FixedString, MyCounter, Id
FROM FixBadChars
WHERE MyCounter = 
        (SELECT MAX(MyCounter) 
        FROM FixBadChars Fixed
        WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);

Vous devriez pouvoir modifier la partie inférieure pour faire une mise à jour plutôt qu'une simple requête, mais je ne l'ai pas essayé. Je suis presque sûr que cela ressemblerait à quelque chose comme ceci:

UPDATE FixBadChars
SET StringToFix = FixedString
WHERE MyCounter = 
        (SELECT MAX(MyCounter) 
        FROM FixBadChars Fixed
        WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);

En ce qui concerne l'évolutivité, j'ai renvoyé environ 170 000 lignes nettoyées en moins de 30 secondes. Encore une fois, je ne suis pas sûr de faire une mise à jour, mais c'était sur mon ordinateur portable qui est assez lent avec seulement 6 Go de RAM.

Kenneth Fisher
la source
0
Declare @String nchar(2000)='hg$%^AB,.:23ab-=+'

Declare @NewString VARCHAR(2000)=''
Declare @Lenght int=LEN(@String)
Declare @Index int=1

WHILE (@Index <= @Lenght)
BEGIN
    Declare @Letter nchar(1)=Substring(@String,@Index,1);
    Declare @ASCII int=ASCII(@Letter);
    If((@ASCII >= 48 and @ASCII <= 57) or (@ASCII >= 97 and @ASCII <= 122) or (@ASCII >= 65 and @ASCII <= 90))
    BEGIN
        SET @NewString += @Letter
    END
    ELSE
    BEGIN
        SET @NewString += ' '
    END
    SET @Index+=1

END
Select @NewString
William Mendoza
la source