Gibt es ein T-SQL-Äquivalent für die Interpunktion wie [0-9] für Zahlen und [az] für Buchstaben?


8

Gibt es ein T-SQL-Äquivalent zu den Mustern [0-9]und [a-z], mit dem ich Werte aus einer Spalte abrufen kann, die Interpunktion enthält?

Zum Beispiel:

Create Table #Test
(
Value   VarChar(10)
) 
Insert Into #Test
Values ('123a'), ('456b'), ('12ABC'),('AB!23'),('C?D789')

Select      *
From        #Test
Where       Value like '[0-9][0-9][0-9][a-z]'

Dies würde Werte zurückgeben, bei denen die ersten 3 Zeichen Zahlen zwischen 0 und 9 sind und das letzte Zeichen ein Buchstabe zwischen a und z ist, also Dinge wie 123aund zurückgeben 456bwürde, aber keinen Wert von zurückgeben würde 12ABC.

Ich möchte wissen, ob es ein Äquivalent für Interpunktion gibt, wie [0-9]für Zahlen und [a-z]für Buchstaben, damit es zurückkehrt AB!23und C?D789?

Wenn ich einen regulären Ausdruck verwenden könnte, könnte ich den Ausdruck verwenden ^[a-zA-Z0-9]*$, um alphanumerische Zeichen in einer Zeichenfolge abzugleichen.

Where       Value like '^[a-zA-Z0-9]*$'

Gibt es dafür ein SQL-Äquivalent?

Ich kenne solche Dinge, die in RegEx ausgeführt werden können, aber ich benötige sie in T-SQL. Ich kann keine benutzerdefinierten Assemblys auf diesen Server laden und kann daher keine regulären Ausdrücke verwenden.

Die reale Spalte ist varchar (200) . Die Sortierung lautet Latin1_General_CI_AS. Ich verwende SQL Server 2012 Standard Edition.


Antworten:


12

Die größte Schwierigkeit, eine genaue Lösung zu finden, besteht darin, genau zu definieren , welche Zeichen eingeschlossen (oder ausgeschlossen) werden sollen, je nachdem, welche Richtung für die Operation sinnvoller ist. Bedeutung:

  • Sprechen wir über VARCHAR/ ASCII-Daten oder NVARCHAR/ Unicode-Daten? Die Liste der Satzzeichen für ASCII-Daten hängt von der Codepage ab, die wiederum von der Sortierung abhängt. ( In dieser Frage beschäftigen wir uns mit ASCII-Daten ).
  • Handelt es sich um Suchanfragen, bei denen zwischen Groß- und Kleinschreibung unterschieden wird?
  • Auf welche Sortierung ist die Spalte eingestellt? In der Sortierung werden sowohl die Codepage als auch die Groß- und Kleinschreibung angegeben. ( In dieser Frage haben wir es zu tunLatin1_General_CI_AS )
  • ist der Begriff „Zeichensetzung“ nur Standardsatzzeichen (zB bedeuten ., ,, ;, :, usw.) oder bedeutet es , nicht-alphanumerische Zeichen?
  • Sind Leerzeichen enthalten?
  • Sind Steuerzeichen enthalten?
  • Was über Währungssymbole wie ¢, £, ¥, etc?
  • Was ist mit Symbolen wie ©und ?
  • Welche Zeichen gelten als "Alpha"? Sind nicht-englische Zeichen wie Â, É, Ñ, ß, Þenthalten?
  • Was ist mit dem / -Zeichen, da sich diese Frage mit Tastaturen in Großbritannien befasst (siehe Diskussion zu dieser Frage) ?Ææ

Um die Klarheit hinsichtlich des erwarteten Verhaltens zu verbessern, werden in der folgenden Abfrage alle 256 Zeichen des Latin1-Zeichensatzes (dh Code Seite 1252) und die Funktionsweise von zwei Varianten der von @ Shaneis vorgeschlagenen Lösung angezeigt . Das erste Feld (gekennzeichnet als Latin1_General_CI_AS) zeigt die LIKEvon @Shaneis vorgeschlagene Klausel (zum Zeitpunkt dieses Schreibens) und das zweite Feld (gekennzeichnet als Latin1_General_100_BIN2) zeigt eine Modifikation, bei der ich die Kollatierung überschrieben habe, um eine binäre anzugeben (dh eine Kollatierung, die mit endet _BIN2; _BINSortierungen sind veraltet, verwenden Sie sie also nicht, wenn Sie Zugriff auf die _BIN2Versionen haben. Dies bedeutete, dass ich auch den A-ZBereich hinzufügen musste, um Großbuchstaben herauszufiltern, da bei der aktuellen Sortierung die Groß- und Kleinschreibung nicht berücksichtigt wird:

;WITH nums AS
(
  SELECT TOP (256) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1) AS [Decimal]
  FROM   [master].[sys].[all_objects]
)
SELECT nm.[Decimal],
       CHAR(nm.[Decimal]) AS [Character],
       CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9]%'
               THEN 'x' ELSE '' END AS [Latin1_General_CI_AS],
       CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9A-Z]%' COLLATE Latin1_General_100_BIN2
               THEN 'x' ELSE '' END AS [Latin1_General_100_BIN2]
FROM   nums nm;

AKTUALISIEREN

Es sollte erwähnt werden, dass WENN man wirklich versucht, Zeichen zu finden, die als "Interpunktion" (und nicht als "Währungssymbol", "mathematisches Symbol" usw.) klassifiziert sind, und WENN es nicht verboten ist, SQLCLR zu verwenden / einen Benutzer zu laden Assembly (SQLCLR wurde mit SQL Server 2005 eingeführt, und ich habe noch keinen guten Grund gefunden, dies nicht zuzulassen, insbesondere da Azure SQL Database V12 SAFEAssemblies unterstützt ). Dann können Sie reguläre Ausdrücke verwenden, jedoch nicht aus dem Grund, den die meisten Benutzer verwenden würde raten.

Anstatt reguläre Ausdrücke zu verwenden, um einen funktionaleren Zeichenbereich zu erstellen, oder sogar etwas wie \w(dh ein "Wort" -Zeichen) zu verwenden, können Sie die Unicode-Kategorie der Zeichen angeben, nach denen Sie filtern möchten, und es gibt mehrere definierte Kategorien ::

https://www.regular-expressions.info/unicode.html#category

Sie können sogar den Unicode-Block angeben, nach dem gefiltert werden soll, z. B. "InBengali" oder "InDingbats" oder "InOptical_Character_Recognition" usw.:

https://www.regular-expressions.info/unicode.html#block

Es gibt zahlreiche Beispiele zum Erstellen von RegEx-Funktionen für SQL Server (obwohl die meisten Beispiele nicht den bewährten Methoden von SQLCLR entsprechen), oder Sie können die kostenlose Version der SQL # -Bibliothek (die ich erstellt habe) herunterladen und die skalare RegEx_IsMatch- Funktion wie folgt verwenden ::

SQL#.RegEx_IsMatch(Unicode-String-Expression, N'\p{P}', 1, NULL)

Der \p{P}Ausdruck bedeutet \p= Unicode-Kategorie und {P}= alle Interpunktion (im Gegensatz zu einer bestimmten Art von Interpunktion, wie z. B. "Connector-Interpunktion"). UND, die Kategorie "Interpunktion" umfasst alle Interpunktionen in allen Sprachen! Sie können die vollständige Liste auf der Unicode.org-Website über den folgenden Link anzeigen (derzeit befinden sich 717 Codepunkte in dieser Kategorie):

http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AGeneral_Category%3DPunctuation%3A%5D

Eine aktualisierte Version der Testabfrage oben gezeigt, einschließlich eines anderen Feld , das verwendet SQL # .RegEx_IsMatch mit \p{P}, und die Ergebnisse aller drei Tests für alle 256 Zeichen von Codepage 1252 (dh Latin1_General) hat auf PasteBin.com bei gepostet:

T-SQL-Abfrage und Ergebnisse zum Filtern von Zeichentypen


UPDATE
Folgendes wurde in der zugehörigen Diskussion erwähnt:

Sie haben einen guten Punkt in Bezug auf akzentuierte Zeichen gemacht, da es sich um Hotelnamen aus der ganzen Welt handelt. Die Namen enthalten akzentuierte Zeichen. Für mein Problem möchte ich diese als gültige Alpha-Zeichen klassifizieren.

In diesem Fall:

  1. Der Latin1-Zeichensatz / die Codepage enthält 11 nicht englische Zeichen, die nicht mit dem a-zBereich übereinstimmen . Sie sind : ð Ð Þ þ œ Œ š Š ž Ž Ÿ. Diese müssen dem Platzhalter hinzugefügt werden, und obwohl dies im Moment nicht erforderlich ist, würde es nicht schaden, sie hinzuzufügen, A-Zdamit das Muster bei einer Sortierung mit Groß- und Kleinschreibung genauso gut funktioniert. Das Endergebnis ist:
    LIKE '%[^a-zA-Z0-9ðÐÞþœŒšŠžŽŸ]%'

  2. In Anbetracht der Tatsache, dass diese Daten "Hotelnamen aus der ganzen Welt" enthalten können, würde ich dringend empfehlen, den Datentyp der Spalte so zu ändern NVARCHAR, dass Sie alle Zeichen aus allen Sprachen speichern können. Wenn Sie dies VARCHARbeibehalten, besteht ein sehr hohes Risiko für Datenverluste, da Sie nur die lateinischen Sprachen darstellen können und nicht einmal vollständig für diejenigen, die die sechs zusätzlichen Unicode-Kategorien enthalten, die zusätzliche lateinische Zeichen enthalten.


5

Ich vereinfache dies möglicherweise ein wenig, aber wenn wir sagen, dass beim Entfernen alphanumerischer Werte nur noch Interpunktion übrig bleibt, wird im Folgenden nach Zeichenfolgen gesucht, die nicht alphanumerische Zeichen enthalten.

Create Table #Test
(
Value   VarChar(10)
) 
Insert Into #Test
Values ('123a'), ('456b'), ('12ABC'),('AB!23'),('C?D789')

-- Original
Select      *
From        #Test
Where       Value like '[0-9][0-9][0-9][a-z]'

-- Non Alpha-numeric
SELECT * FROM #Test WHERE Value LIKE '%[^a-z0-9]%';

DROP TABLE #Test;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.