it-swarm.com.de

Abfrage zum Suchen von Zeilen mit ASCII Zeichen in einem bestimmten Bereich)

Ich verwende einige Skripte aus einem anderen Thema, aber die akzeptierte Antwort funktioniert nicht für alle meine Datenszenarien. Ich hätte meine Frage zum Original gestellt Wie man nach Nicht-Ascii-Charakteren sucht Post, aber ich habe noch nicht genug Ruf, um zu kommentieren oder zu stimmen.

Fragen:

Meine Tests

Ich habe SQL Fiddle mit Beispieldaten, der gespeicherten Prozedur aus einer der Antworten und Abfragen erstellt, um das Problem zu demonstrieren.

Abfrage 1: sample_table

-- Note: The "bad dash" row has char(150)

SELECT * FROM sample_table;

+-------------------+
|    DataColumn     |
+-------------------+
| test - good dash  |
| test – bad dash   |
+-------------------+

Abfrage 2: Die andere Antwort von John zeigt die Zeile "Bad Dash" mit char (150):

SELECT dbo.Find_Invalid_Chars(DataColumn) [Invalid Characters]
FROM sample_table
WHERE dbo.Find_Invalid_Chars(DataColumn) IS NOT NULL;

+----------------------+
|  Invalid Characters  |
+----------------------+
| test [150] bad dash  |
+----------------------+

Abfrage 3: Die akzeptierte Antwort von Martin Smith gibt keine Ergebnisse zurück :

SELECT DataColumn AS [Bad Data]
FROM sample_table
WHERE DataColumn LIKE '%[' + CHAR(127)+ '-' +CHAR(255)+']%' COLLATE Latin1_General_100_BIN2;

+------------+
| [Bad Data] |
+------------+

-- No rows returned.

Schlussfolgerung

Leider muss ich häufig Zeichen innerhalb (oder außerhalb) eines Bereichs in Datenbanken finden, in denen ich keine gespeicherten Prozeduren erstellen kann. Ich würde wirklich gerne eine Lösung für die akzeptierte Antwort oder eine einfache finden Skript, für das keine Objekte erstellt werden müssen (einschließlich temporärer Tabellen).

Irgendwelche Vorschläge? Danke im Voraus.

EDIT 1: Die Lösung kann keine Objekte oder Einstellungen in der Datenbank ändern oder hinzufügen. Ich suche nach einer eigenständigen Abfrage, die Zeilen mit einem oder mehreren Zeichen in einem Bereich zwischen zwei CHAR() -Nummern auswählt, unabhängig von ASCII oder Extended ASCII Nummer geliefert.

EDIT 2: Die DataColumn kann sich entweder in VARCHAR oder NVARCHAR befinden. Ich habe keine Kontrolle darüber und hoffe, eine eigenständige Abfrage zu finden, die für beide funktioniert. Der Zweck der Abfrage besteht darin, Zeichen in der Quelltabelle/-spalte zu finden, die von einigen Softwareanwendungen nicht korrekt behandelt werden. Die Anwendungen interpretieren die Quelle korrekt, haben jedoch manchmal Probleme mit Zeichen außerhalb der "Standard" -Bereiche, obwohl die Bereiche je nach Anwendung variieren.

6
Fred

Warum funktioniert die akzeptierte Antwort nicht für char (150)?

Eigentlich schon. Das Problem ist, dass Ihr Test schlecht/ungültig ist. Die Testspalte DataColumn verwendet NVARCHAR anstelle von VARCHAR. Das Zeichen selbst funktioniert in beiden Datentypen, aber das Verhalten ist unterschiedlich, da es jeweils verwendet wird:

  • In der Funktion Find_Invalid_Chars() (d. H. Der "anderen" Antwort) wird die Zeichenfolge wieder in VARCHAR konvertiert, da dies der Datentyp des Eingabeparameters für diese Funktion ist. In diesem Fall funktioniert es wie erwartet (obwohl ich glaube, dass es viel effizienter als diese Schleife gemacht werden kann, aber das ist für ein anderes Mal ;-)
  • In der Abfrage LIKE (dh der "akzeptierten" Antwort) wird das erweiterte und verkettete Ergebnis von '%[' + CHAR(127)+ '-' +CHAR(255)+']%' tatsächlich in NVARCHAR konvertiert, da dies der Datentyp der Spalte ist, mit der verglichen wird (und NVARCHAR hat eine höhere Priorität für den Datentyp), daher verhält sich die Funktion LIKE nicht wie erwartet: Entweder wird das Zeichen CHAR(255) einem anderen Codepunkt zugeordnet, und/oder das Zeichen CHAR(150) in der Spalte selbst wird einem anderen Codepunkt zugeordnet (das Zeichen CHAR(127) ändert sich nicht, da es im Standardbereich ASCII liegt). In beiden Fällen führt die Konvertierung in NVARCHAR dazu, dass der numerische Wert des Zeichens "En Dash" ("-") nicht mehr innerhalb dieses Bereichs liegt. Das heißt, die Funktion LIKE sucht nach Werten y zwischen 127 Und x (wobei x> = 128) und y für das Zeichen "En Dash" ist jetzt> x. Während in VARCHARx = 255 und y = 150.

Die schnelle Lösung, um zu sehen, dass es funktioniert, besteht einfach darin, den Datentyp NVARCHAR der Spalte DataColumn in VARCHAR zu ändern (ja, entfernen Sie einfach das anfängliche "N"). Erstellen Sie dann das Schema neu und führen Sie es aus. Die Abfrage LIKE verhält sich wie erwartet.

Im Folgenden wird möglicherweise erläutert, warum beim Erstellen der Testspalte NVARCHAR die Abfrage LIKE nicht mit der Zeile übereinstimmt:

SELECT UNICODE(CHAR(127)) AS [CHAR(127)],
       UNICODE(CHAR(150)) AS [CHAR(150)],
       UNICODE(CHAR(255)) AS [CHAR(255)];

/*
CHAR(127)     CHAR(150)     CHAR(255)
127           8211          255
*/

Wie Sie in den Ergebnissen unter der Abfrage sehen können, wurde der "fehlerhafte Bindestrich", der CHAR(150) war, zu NCHAR(8211), wenn er in der Spalte NVARCHAR gespeichert wurde. Und da dieses Prädikat eine binäre Kollatierung verwendet (im Allgemeinen das Richtige in diesem Szenario), wurden die Codepunkte/-werte und nicht die Zeichen betrachtet. Daher suchte die LIKE -Klausel nach Zeichen mit Werten zwischen 127 und 255, und 8211 liegt normalerweise nicht in diesem Bereich ;-).

PS Bitte beachten Sie, dass die Funktion CHAR(150) can Verschiedene Zeichen oder sogar NULL zurückgibt, basierend auf der Standardkollatierung der Datenbank, in der Sie sich befinden Führen Sie diese Funktion aus. Dies liegt daran, dass VARCHAR -Daten auf Codepages basieren und diese durch die Sortierung bestimmt werden. Die beim Ausführen der Funktion CHAR() verwendete Kollatierung ist die Standardkollatierung der aktiven/aktuellen Datenbank. Dies wirkt sich auf die Werte 128 bis 255 aus. Die Werte 0 bis 127 geben unabhängig von der Sortierung immer dieselben Zeichen zurück, da dies der Standardzeichensatz ASCII ist und für alle in SQL Server unterstützten Codeseiten gleich ist (obwohl nicht auf allen Codepages im Allgemeinen).

PPS AUCH ich habe gerade einen kleinen Unterschied in der Logik zwischen der Funktion und der Abfrage festgestellt (dh die beiden Antworten aus der verknüpften Frage): CHAR(127) wird in der Find_Invalid_Chars()-Funktion als gut/gültig angesehen, aber als schlecht/ungültig in der Abfrage LIKE. Wenn ich es wäre, würde ich CHAR(127) als gültig betrachten, da es Teil des Standardzeichensatzes ASCII ist. Aber Sie müssen entscheiden, was Sie davon halten. Beachten Sie diesen Unterschied, falls Sie die Syntax LIKE ein wenig anpassen müssen.


Gegeben:

  1. Der Zweck der Abfrage besteht darin, Zeichen in der Quelltabelle/-spalte zu finden, die von einigen Softwareanwendungen nicht korrekt behandelt werden.

    und:

  2. Die Daten können entweder in VARCHAR oder NVARCHAR sein.

Ich würde sagen, dass:

  1. Sie nicht möchten NVARCHAR Quelldaten in VARCHAR konvertieren, da es möglicherweise "am besten passende" Zuordnungen gibt, die ungültige Quellzeichen in gültige Zeichen übersetzen, aber Eine oder mehrere Ihrer Softwareanwendungen verwenden möglicherweise keine "Best-Fit" -Zuordnungen.

    SELECT NCHAR(178) AS [Unicode], -- Superscript 2 (U+00B2)
           CONVERT(VARCHAR(5), NCHAR(178)
                       COLLATE SQL_Latin1_General_CP1_CI_AS) AS [CodePage-1252],
           CONVERT(VARCHAR(5), NCHAR(178)
                       COLLATE Turkmen_100_CI_AS) AS [CodePage-1250]
    
    /*
    Unicode    CodePage-1252    CodePage-1250
    ²          ²                2
    */
    
  2. Es ist wahrscheinlich zuverlässiger, nach Zeichen nicht in einem bestimmten "gültigen" Bereich zu suchen, als nach Zeichen in einem bestimmten ungültigen Bereich, insbesondere wenn es sich um NVARCHAR handelt, das = enthält viel mehr als 256 Zeichen.
  3. Sie könnten mit einer einzigen Abfrage davonkommen if Der "gültige" Bereich liegt immer zwischen den Werten 0 und 127 (da diese Werte in beiden Fällen gleich sind). Wenn Sie jedoch Werte über 127 angeben müssen, benötigen Sie eine Abfrage für VARCHAR und eine für NVARCHAR.

Alles was gesagt wird:

  • Die folgende Abfrage gibt Zeilen zurück, die mindestens ein Zeichen enthalten, das nicht im Bereich von 0 - 127 für VARCHAR und NVARCHAR liegt. Es funktioniert jedoch nur mit NVARCHAR - Spalten für Werte über 127.

    SELECT *
    FROM   (VALUES (NCHAR(178)), (NCHAR(8211)), (N''), (NULL), (N'xy' + NCHAR(165)),
               (N'AA'), (N'mM' + NCHAR(999) + N'Nn'), (N'#!~()')) tmp(TestValue)
    WHERE  tmp.[TestValue] LIKE N'%[^' + NCHAR(0) + N'-' + NCHAR(127)
              + N']%' COLLATE Latin1_General_100_BIN2;
    
    /*
    TestValue
    ²
    –
    xy¥
    mMϧNn
    */
    
  • Die folgende Abfrage gibt auch Zeilen zurück, die mindestens ein Zeichen enthalten, das nicht im Bereich von 0 - 127 liegt, jedoch nur für VARCHAR - Spalten funktioniert. Es erlaubt jedoch die Verwendung von Werten zwischen 128 und 255.

    SELECT *
    FROM   (VALUES (CHAR(178)), (CHAR(150)), (''), (NULL), ('AA'), ('#!~()'),
            ('xy' + CONVERT(VARCHAR(5), NCHAR(165) COLLATE Latin1_General_100_BIN2)),
            ('mM' + CONVERT(VARCHAR(5), NCHAR(199) COLLATE Latin1_General_100_BIN2) + 'Nn')
           ) tmp(TestValue)
    WHERE  tmp.[TestValue] LIKE '%[^' + CHAR(0) + '-' + CHAR(127)
              + ']%' COLLATE Latin1_General_100_BIN2;
    
    /*
    TestValue
    ²
    –
    xy¥
    mMÇNn
    */
    

Bezüglich:

Die Anwendungen interpretieren die Quelle korrekt, haben jedoch manchmal Probleme mit Zeichen außerhalb der "Standard" -Bereiche, obwohl die Bereiche je nach Anwendung variieren.

  1. Ich bin mir nicht sicher, ob es Probleme mit einigen Zeichen geben kann, wenn die App die Quelldaten richtig interpretiert, es sei denn, Sie haben gemeint, dass sie die Daten "meistens" richtig interpretieren.
  2. Die Bereiche, die je nach Anwendungssound variieren, erfordern möglicherweise eine detailliertere Untersuchung, als dies in einem einfachen Q & A-Format wie diesem möglich ist. Dieses Verhalten kann darauf zurückzuführen sein, dass sie unterschiedliche Treiber für die Verbindung verwenden (ODBC/OLEDB/usw.), in welcher Sprache sie geschrieben sind, welche Annahmen sie über die Daten treffen, die sie erhalten, und so weiter. Einige Probleme können möglicherweise mit einer Konfiguration (keine Codeänderung) der App behoben werden, andere können nur mit einer Codeänderung usw. behoben werden.
4
Solomon Rutzky