Первісне питання було "Як параметризувати запит ..."
Дозвольте тут констатувати, що це не відповідь на початкове запитання. У цьому вже є деякі демонстрації в інших хороших відповідях.
З урахуванням сказаного, ідіть уперед і позначте цю відповідь, похитніть її, позначте її як не відповідь ... робіть все, що ви вважаєте правильним.
Див. Відповідь від Марка Бранкета за кращою відповіддю, яку я (та 231 інші) підтримали. Підхід, наведений у його відповіді, дозволяє 1) для ефективного використання змінних зв'язувати, і 2) для предикатів, які є спірними.
Вибрана відповідь
Я хочу тут звернутись - це підхід, наведений у відповіді Джоела Спольського, відповідь "обрана" як правильна відповідь.
Підхід Джоела Спольського розумний. І це працює розумно, він буде демонструвати передбачувану поведінку та передбачувану продуктивність, з урахуванням "нормальних" значень, і з нормативними крайовими випадками, такими як NULL та порожній рядок. І це може бути достатньо для конкретного застосування.
Але з точки зору узагальнення цього підходу, давайте також розглянемо більш незрозумілі кутові випадки, як, наприклад, коли Name
стовпець містить символи підстановки (як визнано предикатом LIKE.) Символ підстановки, який я бачу, як правило, використовується %
(знак відсотка). Тож давайте зараз розберемося з цим, а пізніше перейдемо до інших справ.
Деякі проблеми з символом%
Розглянемо значення імені 'pe%ter'
. (Для прикладів тут я використовую буквальне значення рядка замість імені стовпця.) Рядок із значенням імені `` pe% ter 'буде повернутий запитом форми:
select ...
where '|peanut|butter|' like '%|' + 'pe%ter' + '|%'
Але той самий рядок не буде повернуто, якщо порядок пошукових термінів буде змінено:
select ...
where '|butter|peanut|' like '%|' + 'pe%ter' + '|%'
Поведінка, яку ми спостерігаємо, є якоюсь дивною. Зміна порядку пошуку пошукових термінів у списку змінює набір результатів.
Цілком зрозуміло, що ми можемо не хотіти pe%ter
відповідати арахісовому маслу, як би він не любив його.
Неясний кутовий корпус
(Так, я погоджусь, що це неясний випадок. Ймовірно, такий варіант, який, швидше за все, не буде перевірений. Ми не очікуємо, що підказки у значенні стовпця. Ми можемо припустити, що програма не дозволяє зберігати таке значення. Але в моєму досвіді я рідко бачив обмеження в базі даних, яке конкретно забороняло символи чи візерунки, які вважалися б символами з правого боку LIKE
оператора порівняння.
Заклеювання отвору
Один із підходів до виправлення цього отвору - це уникнути %
символу підстановки. (Для всіх, хто не знайомий з умовою про вихід на оператора, ось посилання на документацію на SQL Server .
select ...
where '|peanut|butter|'
like '%|' + 'pe\%ter' + '|%' escape '\'
Тепер ми можемо відповідати буквальному%. Звичайно, коли у нас є назва стовпця, нам потрібно буде динамічно вийти з підстановки. Ми можемо скористатися REPLACE
функцією для пошуку подій %
символу та вставлення символу зворотної косої риси перед кожним із них, наприклад:
select ...
where '|pe%ter|'
like '%|' + REPLACE( 'pe%ter' ,'%','\%') + '|%' escape '\'
Таким чином, це вирішує проблему із символом підстановки%. Майже.
Уникнути втечі
Ми визнаємо, що наше рішення ввело ще одну проблему. Характер втечі. Ми бачимо, що нам також потрібно буде уникати будь-яких випадків втечі самого персонажа. Цього разу ми використовуємо! як персонаж втечі:
select ...
where '|pe%t!r|'
like '%|' + REPLACE(REPLACE( 'pe%t!r' ,'!','!!'),'%','!%') + '|%' escape '!'
Підкреслення теж
Тепер, коли ми перебуваємо в рулоні, ми можемо додати ще одну REPLACE
підстановку підкреслення підкреслення. І просто для розваги, цього разу ми будемо використовувати $ як символ втечі.
select ...
where '|p_%t!r|'
like '%|' + REPLACE(REPLACE(REPLACE( 'p_%t!r' ,'$','$$'),'%','$%'),'_','$_') + '|%' escape '$'
Я віддаю перевагу такому підходу, ніж втечу, оскільки він працює в Oracle і MySQL, а також на SQL Server. (Я зазвичай використовую \ backslash як символ втечі, оскільки це символ, який ми використовуємо в регулярних виразах. Але чому обмежуватись умовністю!
Ті досадні дужки
Також SQL Server дозволяє символам підстановки вважатись буквальними, додаючи їх у дужки []
. Тож ми ще не завершили виправлення, принаймні для SQL Server. Оскільки пари дужок мають особливе значення, нам також потрібно уникнути цих. Якщо нам вдасться належним чином уникнути дужок, то, принаймні, нам не доведеться турбуватися дефісом -
і каратами ^
в дужках. І ми можемо залишити будь-які, %
і _
символи всередині дужок втекли, оскільки ми в основному відключили особливе значення дужок.
Пошук відповідних пар дужок не повинен бути таким складним. Це трохи складніше, ніж обробляти події синглів% та _. (Зверніть увагу, що недостатньо просто уникнути всіх випадків дужок, тому що одинарна дужка вважається буквальною, і її не потрібно уникати. Логіка стає трохи нечіткішою, ніж я можу впоратися, не запускаючи більше тестових випадків .)
Вбудований вираз стає безладним
Це вбудоване вираження в SQL стає все довше і негарніше. Ми, мабуть, можемо змусити його працювати, але небо допомагає бідній душі, яка йде позаду і має розшифрувати її. Оскільки я є прихильником я за вбудовані вирази, я схильний не використовувати його тут, головним чином тому, що мені не хочеться залишати коментар, що пояснює причину безладу, і вибачаюся за це.
Функція де?
Гаразд, тому, якщо ми не розглядаємо це як вбудований вираз у SQL, найближча альтернатива, яку ми маємо, - це визначена користувачем функція. І ми знаємо, що це не прискорить ніяких дій (якщо тільки ми не зможемо визначити індекс на ньому, як ми могли б з Oracle.) Якщо нам доведеться створити функцію, ми можемо краще зробити це в коді, що викликає SQL заява.
І ця функція може мати деякі відмінності в поведінці, залежно від СУБД та версії. (Вигук усім, хто розробляє Java, настільки прагне використовувати взаємозамінно будь-який движок бази даних.)
Знання домену
Ми можемо мати спеціалізовані знання про домен для стовпця (тобто набір допустимих значень, застосованих для стовпця. Ми можемо апріорі знати, що значення, що зберігаються у стовпці, ніколи не будуть містити знак відсотка, підкреслення або дужку пари. У цьому випадку ми просто включимо швидкий коментар, що ці випадки висвітлюються.
Значення, що зберігаються у стовпці, можуть містити символи% або _, але обмеження може вимагати уникнення цих значень, можливо, з використанням визначеного символу, таким чином, що значення LIKE порівняння "безпечні". Знову ж таки, швидкий коментар щодо дозволеного набору значень, зокрема того, який персонаж використовується як символ втечі, і піти з підходом Джоела Спольського.
Але, відсутня спеціалізовані знання та гарантія, нам важливо хоча б розглянути питання щодо розгляду цих незрозумілих кутових випадків і розглянути, чи є поведінка розумною та "відповідно до специфікації".
Інші питання рекапітульовані
Я вважаю, що інші вже достатньо вказали на деякі з найбільш поширених проблемних питань:
Інжекція SQL (прийняття інформації, що представляється інформацією, що надається користувачем, і включення її в текст SQL, а не подання їх через змінні змінні. Використання змінних зв'язків не потрібно, це лише один зручний підхід для запобігання ін'єкції SQL. Є й інші способи боротьби з цим:
план оптимізатора, що використовує сканування індексів, а не пошук індексу, можлива потреба у виразі чи функції для уникнення підстановок (можливий індекс за виразом чи функцією)
використання буквальних значень замість змінних зв'язків впливає на масштабованість
Висновок
Мені подобається підхід Джоела Спольського. Це розумно. І це працює.
Але як тільки я побачив це, я одразу побачив потенційну проблему з цим, і не моя природа дозволяти йому ковзати. Я не хочу критикувати зусилля інших. Я знаю, що багато розробників сприймають свою роботу дуже особисто, тому що вони так багато вкладають у неї і так сильно піклуються про неї. Тож зрозумійте, будь ласка, це не особиста атака. Що я тут визначаю - це проблема, яка виникає у виробництві, а не на тестуванні.
Так, я пішов далеко від початкового питання. Але де ще залишити цю замітку стосовно того, що я вважаю важливим питанням із "обраною" відповіддю на запитання?