Escapezeichenfolge in SQL Server, damit die Verwendung im LIKE-Ausdruck sicher ist

77

Wie kann ich eine Zeichenfolge in der gespeicherten Prozedur von SQL Server maskieren, damit sie sicher im LIKEAusdruck verwendet werden kann ?

Angenommen, ich habe eine NVARCHARVariable wie folgt:

declare @myString NVARCHAR(100);

Und ich möchte es in einem LIKEAusdruck verwenden:

... WHERE ... LIKE '%' + @myString + '%';

Wie kann ich die Zeichenfolge (insbesondere Zeichen, die für den LIKEMustervergleich von Bedeutung sind, z. B. %oder ?) in T-SQL umgehen, damit die Verwendung auf diese Weise sicher ist?

Zum Beispiel gegeben:

@myString = 'aa%bb'

Ich will:

WHERE ... LIKE '%' + @somehowEscapedMyString + '%'

zu passen 'aa%bb', 'caa%bbc'aber nicht 'aaxbb'oder 'caaxbb'.

embedded.kyle
quelle

Antworten:

94

Um Sonderzeichen in einem LIKE-Ausdruck zu maskieren, müssen Sie ihnen ein Escapezeichen voranstellen. Sie können auswählen, welches Escape-Zeichen mit dem ESCAPE-Schlüsselwort verwendet werden soll. ( MSDN Ref )

Dies entgeht beispielsweise dem% -Symbol und verwendet \ als Escape-Zeichen:

select * from table where myfield like '%15\% off%' ESCAPE '\'

Wenn Sie nicht wissen, welche Zeichen in Ihrer Zeichenfolge enthalten sind und Sie sie nicht als Platzhalter behandeln möchten, können Sie allen Platzhalterzeichen ein Escapezeichen voranstellen, z.

set @myString = replace( 
                replace( 
                replace( 
                replace( @myString
                ,    '\', '\\' )
                ,    '%', '\%' )
                ,    '_', '\_' )
                ,    '[', '\[' )

(Beachten Sie, dass Sie auch Ihrem Fluchtzeichen entkommen müssen, und stellen Sie sicher, dass dies das Innere ist, replacedamit Sie nicht den aus den anderen replaceAnweisungen hinzugefügten entkommen .) Dann können Sie so etwas verwenden:

select * from table where myfield like '%' + @myString + '%' ESCAPE '\'

Denken Sie auch daran, mehr Platz für Ihre @ myString-Variable zuzuweisen, da diese mit dem Ersetzen der Zeichenfolge länger wird.

Rory
quelle
Derzeit verwende ich den unter stackoverflow.com/questions/13861004/… genannten Ansatz. Sehen Sie Mängel bei diesem Code?
LCJ
2
@Lijo, das ist in Ordnung. Diese Antwort führt die Escape-Anweisung in C # aus, während die obige Antwort dies in SQL bewirkt, da sie nicht C # -spezifisch ist. In beiden Fällen ist das Ergebnis dasselbe: Entfernen Sie alle Sonderzeichen in Ihrer Suchzeichenfolge und verwenden Sie das Schlüsselwort ESCAPE in Ihrer LIKE-Anweisung.
Rory
Ich denke, Sie müssen auch einem einfachen Anführungszeichen entkommen (indem Sie es durch zwei einfache Anführungszeichen ersetzen, nicht durch \').
Ted Hopp
@ TedHopp - nein, du musst 'für die Zwecke von LIKE nicht entkommen , da es für LIKE kein Sonderzeichen ist. Zum Beispiel funktioniert dies gut:declare @s nvarchar(max); set @s = '%''%'; with a_cte as ( select 'I''m adam' as aColumn ) select * from a_cte where aColumn like @s;
Rory
@ TedHopp - Sie beziehen sich wahrscheinlich nur auf die Notwendigkeit, zwei 'zu verwenden, um ein einzelnes Anführungszeichen in einer Zeichenfolgenkonstante zu definieren. Ja, das müssen Sie tun, aber der resultierende Zeichenfolgenwert enthält nur ein einfaches Anführungszeichen: Das Escapezeichen wird nur ausgeführt, um das einfache Anführungszeichen in die Zeichenfolgenvariable zu übernehmen, wenn es als konstanter Wert deklariert wird. Sie könnten das 'irgendwo auswählen und müssten es nicht entkommen.
Rory
19

Hatte ein ähnliches Problem (mit NHibernate, daher wäre das Schlüsselwort ESCAPE sehr schwierig gewesen) und löste es mit den Klammerzeichen. So würde Ihre Probe werden

WHERE ... LIKE '%aa[%]bb%'

Wenn Sie Beweise benötigen:

create table test (field nvarchar(100))
go
insert test values ('abcdef%hijklm')
insert test values ('abcdefghijklm')
go
select * from test where field like 'abcdef[%]hijklm'
go
Trocknet Van Hansewijck
quelle
1
Dies ist die beste Antwort. Verlässt sich nicht auf Flucht und funktioniert für alle Saiten.
John
Ich denke, dies ist das einfachste und dem, was der Fragesteller gesucht hat, am nächsten. Um nicht zu sagen, dass ESCAPE in einigen Fällen nicht so nützlich ist.
Bitoolean
2
Es gibt immer noch keine Erklärung, wie man zuverlässig eine Liste von Zeichen erhält, die maskiert werden müssen, oder wie man eine beliebige Zeichenfolge nimmt und sie ordnungsgemäß maskiert.
Binki
14

Anstatt alle Zeichen in einer Zeichenfolge zu maskieren, die für die Mustersyntax von besonderer Bedeutung sind, da Sie einen führenden Platzhalter im Muster verwenden, ist dies schneller und einfacher.

SELECT * 
FROM YourTable
WHERE CHARINDEX(@myString , YourColumn) > 0

In Fällen, in denen Sie keinen führenden Platzhalter verwenden, sollte der oben beschriebene Ansatz vermieden werden, da kein Index für verwendet werden kann YourColumn.

In Fällen, in denen der optimale Ausführungsplan je nach Anzahl der übereinstimmenden Zeilen variiert, sind die Schätzungen möglicherweise besser, wenn LIKEdie Syntax mit eckigen Klammern im Vergleich zu beidenCHARINDEX und dem ESCAPESchlüsselwort verwendet wird .

Martin Smith
quelle
Ausgezeichnet! Aber was wäre, wenn es keine führende Wild Card gäbe?
Colin
1
@Colin - Wenn es keinen führenden Platzhalter gab und das Ziel darin bestand, alle Platzhalterzeichen an anderer Stelle in der Zeichenfolge zu maskieren, können Sie =stattdessen einfach verwenden . Die ausgeblendeten Sonderzeichenantworten können dennoch für eine Abfrage nützlich sein, die nach Werten sucht, die mit einem bestimmten Wert beginnen, da LIKEin diesem Fall ein Index verwendet werden kann, dies jedoch CHARINDEXnicht kann.
Martin Smith
4

Sie geben das Escape-Zeichen an. Dokumentation hier:
http://msdn.microsoft.com/en-us/library/ms179859.aspx

Corey Trager
quelle
1
Ich wünschte mir etwas, das bereits jetzt weiß, was in einem LIKE-Ausdruck entkommen muss.
In der Antwort wurde vorgeschlagen, dass Sie Ihr eigenes Escape-Zeichen angeben, damit "aussagekräftige" Zeichen nicht mehr aussagekräftig sind.
Goran
3

Möchten Sie nach Zeichenfolgen suchen, die ein Escape-Zeichen enthalten? Zum Beispiel möchten Sie dies:

select * from table where myfield like '%10%%'.

Wo möchten Sie mit 10% nach allen Feldern suchen? In diesem Fall können Sie die ESCAPE-Klausel verwenden, um ein Escape-Zeichen anzugeben und das Platzhalterzeichen zu maskieren.

select * from table where myfield like '%10!%%' ESCAPE '!'
Vincent Ramdhanie
quelle
Ich habe der Frage ein Beispiel hinzugefügt, was ich möchte.
0

Alternative Escape-Syntax:

WIE Wildcard-Literale

Der JDBC-Treiber unterstützt die Syntax {Escape 'Escape Character'} für die Verwendung von LIKE-Klausel-Platzhaltern als Literale.

SELECT *
FROM tab
WHERE col LIKE 'a\_c' {escape '\'};

db <> Geigen-Demo

Lukasz Szozda
quelle