2009-03-26 9 views

risposta

15

Prima costruisci una stringa con tutti i caratteri che non ti interessano (l'esempio usa l'intervallo 0x20 - 0x7F o 7 bit senza i caratteri di controllo). Ogni carattere è preceduto da |, per l'uso nella clausola escape dopo.

-- Start with tab, line feed, carriage return 
declare @str varchar(1024) 
set @str = '|' + char(9) + '|' + char(10) + '|' + char(13) 

-- Add all normal ASCII characters (32 -> 127) 
declare @i int 
set @i = 32 
while @i <= 127 
    begin 
    -- Uses | to escape, could be any character 
    set @str = @str + '|' + char(@i) 
    set @i = @i + 1 
    end 

Il snippet successivo ricerca qualsiasi carattere che non sia nell'elenco. La% corrisponde a 0 o più caratteri. [] Corrisponde a uno dei caratteri all'interno di [], ad esempio [abc] corrisponde a a, boc. Il^nega l'elenco, ad esempio [^ abc] corrisponde a tutto ciò che non è a, b, o c.

select * 
from yourtable 
where yourfield like '%[^' + @str + ']%' escape '|' 

è necessario il carattere di escape perché altrimenti alla ricerca di personaggi come],% o _ sarebbe rovinare l'espressione LIKE.

Spero che questo sia utile, e grazie al commento di JohnFX sull'altra risposta.

+0

È possibile aggiungere alcuni (o tutti) i caratteri riportati di seguito 32 pure, particolarmente importante sarebbe Carriage Return (13), Line Feed (10) e Tab (9). –

+0

Un buon punto aggiunto – Andomar

+1

Ho trovato la tecnica come il modo più affidabile per farlo in SQL-Server. – cusman

2

probabilmente non è la soluzione migliore, ma forse una query come:

SELECT * 
FROM yourTable 
WHERE yourTable.yourColumn LIKE '%[^0-9a-zA-Z]%' 

Sostituire l'espressione "0-9a-zA-Z" con qualcosa che cattura il set ASCII completo (o un sottoinsieme che il vostro i dati contengono).

+0

Non corrisponde solo alle righe che contengono caratteri ASCII, al contrario solo caratteri ASCII? – Andomar

+0

Il marcatore^nella parte anteriore dell'espressione significa NOT, quindi no. Avrebbe ottenuto qualsiasi riga che avesse almeno un carattere che non era compreso negli intervalli specificati. – JohnFx

+0

Come posso inserire il set completo di ascii in quell'espressione? sono i dati HTML che sto osservando così "/><'etc ... è lì dentro. – TheSoftwareJedi

0

La mia risposta precedente confondeva i dati UNICODE/non-UNICODE. Ecco una soluzione che dovrebbe funzionare per tutte le situazioni, anche se sto ancora incontrando alcune anomalie. Sembra che certi caratteri unicode non ASCII per i caratteri in apice siano confusi con il carattere numerico attuale. Potresti essere in grado di giocare con le regole di confronto per aggirare il problema.

Speriamo che tu abbia già una tabella di numeri nel tuo database (possono essere molto utili), ma nel caso in cui ho incluso il codice per riempirlo parzialmente.

Potrebbe anche essere necessario per giocare con l'intervallo numerico, dal momento che i caratteri Unicode possono andare oltre 255.

CREATE TABLE dbo.Numbers 
(
    number INT NOT NULL, 
    CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (number) 
) 
GO 
DECLARE @i INT 

SET @i = 0 

WHILE @i < 1000 
BEGIN 
    INSERT INTO dbo.Numbers (number) VALUES (@i) 

    SET @i = @i + 1 
END 
GO 

SELECT *, 
    T.ID, N.number, N'%' + NCHAR(N.number) + N'%' 
FROM 
    dbo.Numbers N 
INNER JOIN dbo.My_Table T ON 
    T.description LIKE N'%' + NCHAR(N.number) + N'%' OR 
    T.summary LIKE N'%' + NCHAR(N.number) + N'%' 
and t.id = 1 
WHERE 
    N.number BETWEEN 127 AND 255 
ORDER BY 
    T.id, N.number 
GO 
+0

Il modo in cui lo capisco, ASCII è 7 bit e varchar è 8 bit. Quindi varchar può ancora memorizzare molti caratteri che non sono ascii, come ä o é. – Andomar

+0

Sto vedendo gli stessi risultati. Questo non funziona. – TheSoftwareJedi

+1

ASCII esteso è 8 bit, che è ciò a cui alcune persone si riferiscono quando dicono "ASCII". Modificherò il post anche per limitare il normale ASCII. –

-1

- Questo è un modo molto, molto inefficiente di farlo, ma dovrebbe essere OK per - Tavolini Utilizza una tabella ausiliaria di numeri secondo Itzik Ben-Gan e semplicemente - cerca i caratteri con il bit 7 impostato.

SELECT * 
FROM yourTable as t 
WHERE EXISTS (SELECT * 
       FROM msdb..Nums as NaturalNumbers 
       WHERE NaturalNumbers.n < LEN(t.string_column) 
         AND ASCII(SUBSTRING(t.string_column, NaturalNumbers.n, 1)) > 127) 
3

Tecnicamente, credo che un NCHAR (1) è un carattere ASCII valida se & solo se UNICODE (@NChar) < 256 e ASCII (@NChar) = Unicode (@NChar) anche se questo potrebbe non essere esattamente quello che volevi. Quindi questa sarebbe una soluzione corretta:

;With cteNumbers as 
(
    Select ROW_NUMBER() Over(Order By c1.object_id) as N 
    From sys.system_columns c1, sys.system_columns c2 
) 
Select Distinct RowID 
From YourTable t 
    Join cteNumbers n ON n <= Len(CAST(TXT As NVarchar(MAX))) 
Where UNICODE(Substring(TXT, n.N, 1)) > 255 
    OR UNICODE(Substring(TXT, n.N, 1)) <> ASCII(Substring(TXT, n.N, 1)) 

Questo dovrebbe anche essere molto veloce.

+0

ASCII è solo fino a 127. Anche il tuo numero cte è strano - la soluzione finale dovrebbe usare una tabella di numeri preesistente invece di essa. Altrimenti, è così che lo farei. –

+0

FYI: "Non sembrare strano" non è un criterio che io (o la maggior parte degli uber-geek di questo sito) ci tengo davvero. E il vantaggio di non utilizzare una tabella di numeri preesistente, è che funziona anche se la tabella non è preesistente (cosa che di solito non funziona). Infine, se metti alla prova la mia soluzione, scoprirai che funziona a un livello comparabile ea volte persino migliore di una tabella di numeri preesistente. – RBarryYoung

+0

Non voglio davvero discutere - sono per lo più d'accordo con la tua soluzione. Ma "strano" di solito è difficile da leggere e irrinunciabile. È così che intendevo. Inoltre, non è ASCIUTTO se hai due query diverse che richiedono numeri: devi scrivere due volte la C++ non più gestibile. Leggere i numeri di riga da un join di system_columns su se stesso non è molto semplice, ma leggere i numeri da una tabella di numeri sarebbe molto facile eseguire il debug. –

40

volte ho usato questa dichiarazione "cast" di trovare caratteri "strani"

select 
    * 
from 
    <Table> 
where 
    <Field> != cast(<Field> as varchar(1000)) 
+0

Questo ha funzionato per me ed era molto più veloce della soluzione di RBarryYoung – Trisped

+1

Non funziona se le regole di confronto sono impostate su un confronto" non ASCII " – deerchao

+0

Risposta brillante –

1

ho iniziato con la soluzione di @ CC1960 ma ho trovato un interessante caso d'uso che ha causato il fallimento.Sembra che SQL Server equiparerà determinati caratteri Unicode alle loro approssimazioni non Unicode. Ad esempio, SQL Server considera il carattere Unicode "fullwidth comma" (http://www.fileformat.info/info/unicode/char/ff0c/index.htm) lo stesso di una virgola ASCII standard se confrontato in una clausola WHERE.

Per aggirare questo problema, fare in modo che SQL Server confronti le stringhe come binario. Ma ricordate, nvarchar e varchar binari non corrispondono up (16-bit vs 8-bit), quindi è necessario convertire il vostro varchar indietro fino alla nvarchar di nuovo prima di fare il confronto binario:

select * 
from my_table 
where CONVERT(binary(5000),my_table.my_column) != CONVERT(binary(5000),CONVERT(nvarchar(1000),CONVERT(varchar(1000),my_table.my_column))) 
1

Se sei cercando un carattere unicode specifico, potresti usare qualcosa come sotto.

select Fieldname from 
    (
     select Fieldname, 
      REPLACE(Fieldname COLLATE Latin1_General_BIN, 
      NCHAR(65533) COLLATE Latin1_General_BIN, 
      'CustomText123') replacedcol 
     from table 
    ) results where results.replacedcol like '%CustomText123%' 
2

Qui ya go:

SELECT * 
FROM Objects 
WHERE 
    ObjectKey LIKE '%[^0-9a-zA-Z !"#$%&''()*+,\-./:;<=>[email protected]\[\^_`{|}~\]\\]%' ESCAPE '\' 
Problemi correlati