Екрануйте рядок у SQL Server, щоб його було безпечно використовувати у виразі LIKE


78

Як мені уникнути рядка у збереженій процедурі SQL Server, щоб його було безпечно використовувати у LIKEвиразі.

Припустимо, у мене є така NVARCHARзмінна:

declare @myString NVARCHAR(100);

І я хочу використовувати це у LIKEвиразі:

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

Як мені уникнути рядка (точніше, символів, які мають значення для LIKEзбігу шаблонів, наприклад, %або ?) у T-SQL, щоб його було безпечно використовувати таким чином?

Наприклад, враховуючи:

@myString = 'aa%bb'

Я хочу:

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

відповідати 'aa%bb', 'caa%bbc'але ні 'aaxbb'чи 'caaxbb'.

Відповіді:


94

Щоб уникнути спеціальних символів у виразі LIKE, ви додаєте до них символи втечі. Ви можете вибрати, який символ втечі використовувати з ключовим словом ESCAPE. ( Посилання MSDN )

Наприклад, це уникає символу%, використовуючи \ як символ втечі:

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

Якщо ви не знаєте, які символи будуть у вашому рядку, і ви не хочете розглядати їх як символи підстановки, ви можете додати до всіх символів узагальнення префікс, наприклад:

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

(Зверніть увагу, що вам також потрібно уникнути вашого символу втечі, і переконайтеся, що це внутрішнє, replaceщоб не уникати доданих з інших replaceтверджень). Тоді ви можете використовувати щось подібне:

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

Також не забудьте виділити більше місця для вашої змінної @myString, оскільки вона стане довшою із заміною рядка.


На даний момент я використовую підхід, згаданий у stackoverflow.com/questions/13861004/ ... Чи бачите ви якісь недоліки цього коду?
LCJ

2
@Lijo, це добре. Ця відповідь робить екранування в C #, тоді як наведена вище відповідь робить це в SQL, оскільки вона не є специфічною для C #. У будь-якому випадку результат однаковий: уникніть будь-яких спеціальних символів у вашому рядку пошуку та використовуйте ключове слово ESCAPE у своєму операторі LIKE.
Рорі

Я думаю, вам також потрібно уникнути однієї лапки (замінивши її двома одинарними лапками, а не на \').
Тед Хопп,

@TedHopp - ні, вам не потрібно рятуватися 'для цілей LIKE, оскільки це не спеціальний символ для LIKE. Наприклад, це чудово працює:declare @s nvarchar(max); set @s = '%''%'; with a_cte as ( select 'I''m adam' as aColumn ) select * from a_cte where aColumn like @s;
Рорі

@TedHopp - ви, мабуть, маєте на увазі лише необхідність використовувати два 'для того, щоб визначити одну лапку в рядковій константі. Так, вам потрібно це зробити, але отримане значення рядка має лише одинарну лапку: екранування виконується лише для того, щоб одинична лапка потрапила до рядкової змінної при оголошенні її як постійне значення. Ви можете вибрати 'десь звідти, і вам не потрібно буде його уникати.
Рорі

19

Мав подібну проблему (використання NHibernate, тому ключове слово ESCAPE було б дуже складним) і вирішив її за допомогою символів дужок. Тож ваш зразок став би

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

Якщо вам потрібні докази:

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

1
Це найкраща відповідь. Не покладається на втечу і працює для всіх струн.
Джон

Я думаю, що це найпростіший і найближчий до того, що шукав запитувач. Не кажучи вже про те, що ESCAPE в деяких випадках не такий корисний.
bitoolean

2
Досі немає пояснення того, як надійно отримати список символів, які потребують екранування, або як взяти довільний рядок та правильно його уникнути.
binki

14

Замість того, щоб уникнути всіх символів у рядку, які мають особливе значення в синтаксисі шаблону, враховуючи, що ви використовуєте провідні символи підстановки у шаблоні, це швидше та простіше просто зробити.

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

У випадках, коли ви не використовуєте провідний шаблон, слід уникати наведеного вище підходу, оскільки він не може використовувати індекс на YourColumn.

Крім того , в тих випадках , коли оптимальний план виконання буде варіюватися в залежності від числа співпадаючих рядків оцінки може бути краще при використанні LIKEз квадратної дужкою відводить синтаксису в порівнянні з такCHARINDEX і по ESCAPEключовим словом .


Відмінно! Але що, якби не було провідного wild card?
Колін

1
@Colin - Якби не було провідних символів підстановки, а метою було уникнути всіх символів підстановки в інших місцях рядка, тоді ви можете просто використовувати їх =. Відповіді спеціальних символів, що виходять на екран, все ще можуть бути корисними для запиту, який шукає значення, що починаються з певного значення, хоча, як LIKEможе використовувати індекс у цьому випадку, але CHARINDEXне може.
Martin Smith

4

Ви вказуєте символ втечі. Документація тут:
http://msdn.microsoft.com/en-us/library/ms179859.aspx


1
Я бажав чогось, що вже зараз знає, що потрібно уникнути у виразі, ПОДОБНО.

Відповідь пропонував вказати власного символу втечі, тому "значущі" символи більше не матимуть значення.
Горан

3

Ви хочете шукати рядки, які містять символ втечі? Наприклад, ви хочете:

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

Де ви хочете шукати всі поля з 10%? Якщо це так, тоді ви можете використовувати речення ESCAPE, щоб вказати символ втечі та символ підстановки.

select * from table where myfield like '%10!%%' ESCAPE '!'

Я додав приклад того, що я хочу, до запитання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.