Sostituisci i caratteri speciali in una colonna con spazio


10

Sto cercando di scrivere una query che sostituisce i caratteri speciali con spazio. Il codice seguente aiuta a identificare le righe. (caratteri alfanumerici, virgola e spazio sono validi):

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

Come posso integrare la funzione di sostituzione nell'istruzione select in modo che tutti i caratteri diversi da alfanumerici, virgola e spazio nel set di risultati siano sostituiti da '' (spazio). Questo non funzionerà:

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

Risposte:


11

Se sei sicuro di usare sempre e solo le 26 lettere dell'alfabeto inglese americano (sia maiuscole che minuscole), puoi sicuramente cavartela usando LIKEe / o PATINDEXcon la semplice notazione di intervallo di [a-z](non è necessario utilizzare una "Z" maiuscola quando si utilizza una raccolta senza distinzione tra maiuscole e minuscole).

Ma, se si potrebbe ottenere caratteri non presenti nel it-IT alfabeto ancora disponibile in varie Codice Pages / Regole di confronto per i VARCHARdati (ad esempio Þ= capitale latino "Thorn" = SELECT CHAR(0xDE)), allora si potrebbe aver bisogno di includere quelli della classe di caratteri: [a-z0-9, Þ]. Ovviamente, quali sarebbero questi caratteri extra è basato su una pagina per codice.

Inoltre, tenere presente che sia il tipo di regole di confronto (SQL Server rispetto a Windows) sia le impostazioni di sensibilità (maiuscole, accento, ecc. Sensibili o insensibili) influenzeranno i caratteri inclusi in un determinato intervallo. Ad esempio, le regole di confronto di SQL Server ordinano le lettere maiuscole e minuscole nell'ordine opposto rispetto alle regole di confronto di Windows. Significa che, supponendo un confronto con distinzione tra maiuscole e minuscole per entrambi i tipi di confronto, uno farà AaBb...e l'altro farà aAbB.... L'effetto sarà che arientrerà nel range di A-Zuno di essi, ma non l'altro. E l'intervallo di a-Znon corrisponderà a nessun personaggio in un confronto binario (uno che termina in uno _BINo _BIN2, ma non usare _BIN) dato che il valore di Aè 65 eaè 97, quindi è un intervallo non valido da 97 a 65 ;-). Ci sono troppe varianti per fornire esempi per questo, quindi proverò a pubblicare una spiegazione dettagliata sul mio blog a breve (e poi aggiornerò questo con il link ad esso). Tuttavia, se stai per essere severo nell'accettare solo caratteri inglesi statunitensi (anche se potresti ottenere lettere valide da altre lingue), la tua migliore opzione sarà probabilmente quella di utilizzare il seguente schema e le seguenti regole di confronto:

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

Ora, se stai supportando i NVARCHARdati e puoi ottenere caratteri "word" da varie lingue, allora T-SQL non sarà di grande aiuto in quanto non ha un modo reale di differenziare queste cose. In questo caso, è necessario utilizzare un'espressione regolare (RegEx), in particolare il Replacemetodo / la funzione, e questi sono disponibili solo tramite SQLCLR. Quanto segue mostra un esempio di sostituzione di più caratteri "speciali", lasciando tutte le lettere valide in almeno una lingua:

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); 

Ritorna:

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

L'espressione RegEx significa:

  • \W= una "escape" RegEx che significa "qualsiasi carattere non- parola"
  • \p{Pc}= una "categoria" Unicode di "Punteggiatura, Connettore" (questo è necessario per la corrispondenza solo perché questa "categoria" è specificamente esclusa dalla \Wfuga)
  • -[,]= sottrazione di classe (è necessario per escludere le virgole dalla corrispondenza come "speciale" poiché sono incluse nell'escape \W)

Puoi fare un aggiornamento di una tabella semplicemente emettendo:

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;

Si noti che per questi esempi, ho usato due funzioni disponibili nella libreria SQL # versione gratuita delle funzioni SQLCLR, che ho creato (ma, di nuovo, sono gratuite). Si noti inoltre che ho usato le versioni "4k" che sono più veloci a causa dell'utilizzo NVARCHAR(4000)invece dei NVARCHAR(MAX)tipi di parametri. Se i tuoi dati stanno utilizzando NVARCHAR(MAX), rimuovi semplicemente "4k" dai nomi delle funzioni.

Vedi anche:


5

Ho un post qui che fa qualcosa di simile .

Fondamentalmente sto usando un CTE ricorsivo per andare ripetutamente a sostituire un carattere "cattivo" alla volta. Sto usando STUFF per rimuovere 1 carattere (anche se puoi usarlo per sostituirlo con uno spazio) e PATINDEX per trovare la posizione del personaggio che voglio rimuovere. Puoi modificarlo leggermente per fare quello che stai cercando. Tuttavia crea un elenco "valido", in realtà non aggiorna l'elenco esistente.

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);

Dovresti essere in grado di modificare la parte inferiore per fare un aggiornamento anziché solo una query, ma in realtà non l'ho provato. Sono abbastanza sicuro che sarebbe simile a questo:

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

Per quanto riguarda la scalabilità, ho restituito ~ 170.000 righe pulite in meno di 30 secondi. Ancora una volta non sono sicuro di fare un aggiornamento, ma questo è stato sul mio laptop che è abbastanza lento con solo 6 GB di RAM.


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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.