Шукайте “ціле співпадання слів” у MySQL


75

Я хотів би написати SQL-запит, який шукає ключове слово у текстовому полі, але лише якщо це "ціле слово відповідає" (наприклад, коли я шукаю "rid", він не повинен відповідати "посушливому", але він повинен матч "позбавлення"

Я використовую MySQL.

На щастя, продуктивність у цьому додатку не є критичною, і розмір бази даних, і розмір рядків комфортно малі, але я волів би робити це в SQL, ніж у PHP, що керує нею.

Відповіді:


154

Ви можете використовувати REGEXPі маркери меж [[:<:]]і [[:>:]]слів:

SELECT *
FROM table 
WHERE keywords REGEXP '[[:<:]]rid[[:>:]]'

Оновлення на 2020 рік: (насправді 2018+)

MySQL оновив свій RegExp-Engine у ​​версії 8.0.4, тому вам тепер потрібно буде використовувати " стандартний " маркер межі слова \ b:

SELECT *
FROM table 
WHERE keywords REGEXP '\\brid\\b'

Також пам’ятайте, що вам потрібно уникнути зворотної косої риски, поставивши другу зворотну риску.


2
Тільки примітка, рядки, що використовують спеціальні символи регулярних виразів, повинні бути екрановані.
Кенстон Чой,

1
Але ще одна проблема налаштування межі слова полягає в тому, що вона може розглядати крапки як межі слів, тому, якщо ви маєте намір збігати імена, це може не працювати належним чином. виберіть 'RC Sproul' регулярний вираз 'R \ .C \.'; / * Повертає 1 * / ... виберіть 'RC Sproul' regexp '[[: <:]] R \ .C \. [[:>:]]' / * Повертає 0 * /
Кенстон Чой

1
@LukeH - Дякую. Це круто. і я використовував RLIKE, чи є якась різниця в обох REGEX та RLIKE.
Shail Paras

1
Мені було корисно.
Xcoder

2
І лише примітка щодо використання змінної php у вашому запиті mysql:'[[:<:]]" . $rid . "[[:>:]]'
stackunderflow

29

Знайшов відповідь, щоб запобігти [[::<::]]зіткненню класичної межі слова зі спеціальними символами, наприклад @ # $% ^ & *

Замінити ..

SELECT *
FROM table 
WHERE keywords REGEXP '[[:<:]]rid[[:>:]]'

З цим..

SELECT *
FROM table 
WHERE keywords REGEXP '([[:blank:][:punct:]]|^)rid([[:blank:][:punct:]]|$)'

Останнє збігається (пробіл, вкладка тощо) || (кома, дужка тощо) || початок / кінець рядка. Більш «закінчена» відповідність межі слова.


Цей код для мене не працює. Я отримую: Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''([[[:blank:][:punct:]]' at line 3 SQLState: 42000 ErrorCode: 1064Будь-які ідеї?
Solver42

@ Solver42 Я щойно перевірив наведений вище запит за допомогою mysql 5.6.21, і він працює як зазвичай. Спробуйте видалити першу дужку з'([[[
Ricky Boyce

Я спробував це, але отримав ту ж помилку. Однак це зробило фокус: ([[: blank:]] | | [[: punct:]] | ^) rid ([[: punct:]} | | [[: blank:]] | $)
Solver42

5

Ви можете використовувати likeмаркер узагальнення, щоб вловити можливості (на початку, в кінці, посередині та поодинці), цього може бути достатньо:

виберіть бла-бла-бла, де стовпець на зразок 'rid%' або стовпець на зразок '% rid' або стовпець на зразок '% rid%' або column = 'rid'


Залежно від ситуації слід також обережно ставитись до пунктуації. Наприклад, ніхто з них не повернеться "позбутися".
Грег Лівер

4
Я вважаю, що запиту недостатньо. Що можна сказати про такий текст, як "позбутися" чи "(позбутися)"?
wenqiang

Хороша відповідь, хороше спостереження, просте рішення: ви можете адаптувати запит за допомогою спеціальних рядків, щоб задовольнити потреби ваших даних. Наприклад, додайте кілька рядків , як: or column like '% rid, %' or column like 'rid, %'. Або скористайтеся наведеним вище способом регулярного виразу.
stackunderflow

4

Використовуйте регулярний вираз із межами слів, але якщо вам потрібен також пошук, нечутливий до наголосу, зауважте, що REGEXP є однобайтовим оператором, тому не варто мати збірок utf8_general_ci, збіг не буде чутливим до наголосу.

Щоб збігатися як з наголосом, так і з цілим, вкажіть слово, написане так само, як і (застаріла) функція PHP sql_regcase ().

Насправді:

  • utf8_general_ci дозволяє зробити рівність (WHERE поле = значення) регістр і наголос нечутливий пошук, але це не дозволяє вказати цілу відповідність слова (маркери меж слів не розпізнаються)

  • LIKE дозволяє здійснювати пошук, нечутливий до регістру та наголосу, але вам потрібно вручну вказати всі комбінації можливих символів меж слова (маркери меж слова не розпізнаються)

  • межі слів [[: <:]] та [[:>:]] підтримуються в REGEXP, який є однобайтовою функцією, тому не виконуйте акцентований нечутливий пошук.

Рішення полягає у використанні REGEXP з межами слів та словом, модифікованим так, як це робить sql_regcase.

Використовується на http://www.nonsolodiete.it


1
select * from table where Locate('rid ', FieldToSearch) > 0 
      or Locate(' rid', FieldToSearch) > 0

Це впорається з пошуком позбавлення там, де йому передує або слідує пробіл, ви можете розширити підхід, враховуючи.,?! і так далі, не елегантно, але легко.


1

Це найкраща відповідь, яку я сам придумав до цього часу:

SELECT * FROM table 
WHERE keywords REGEXP '^rid[ $]' OR keywords REGEXP ' rid[ $]'

Я б спростив це так:

SELECT *
FROM table
WHERE keywords REGEXP '[^ ]rid[ $]'

але [^] має особливе значення "НЕ пробіл", а не "початок рядка або пробіл".

Як REGEXP порівнюється з багатьма умовами LIKE? (Не те, що продуктивність має значення в цьому додатку.)


2
Якщо ви зробили це [^], я думаю, що другий спрацював би. ^ - це "не", якщо це перший символ у наборі, IIRC.
Тревіс Дженсен

Цікаво, чи має SQL REGEXP поле "межа слова", як Perl \ b? Це обробляло пробіли, пунктуацію тощо
Енді Уайт,

@Andy, MySql використовує [[: <:]] та [[:>:]] як маркери меж слова.
LukeH

@Oddthinking, маркери меж слова - це, мабуть, те, що вам слід використовувати. Див. Мою відповідь для прикладу.
LukeH

1
Або ви можете написати це як: SELECT * FROM table WHERE
keyword REGEXP
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.