#mysql #sql
#mysql #sql
Вопрос:
У меня есть такой сценарий:
Я хочу проверить наличие определенных слов, и если они соответствуют термину, мне придется обновить содержимое этой страницы и связать его с термином. Но сейчас я сосредоточен на получении страниц контента, часть содержимого которых совпадает с определенным термином.
Это идея того, что мне нужно сделать, но это не работает, поскольку подзапрос возвращает более одного поля.
Я хочу найти, ГДЕ m.module_content похож на любой из имеющихся у меня терминов, но он должен сверяться с ними всеми.
SELECT m.module_termid, t.term_name, m.module_name, m.module_content
FROM modules m
JOIN terms t ON m.module_termid = t.term_id
WHERE m.module_content LIKE '%' || (SELECT term_name FROM terms) || '%'
module_content содержит текст в формате html, поэтому в конечном итоге все, что мне нужно будет сделать, это, если он соответствует термину, и это еще не ссылки, я добавлю ссылку на этот конкретный термин.
Что здесь лучше всего сделать? (Я использую mysql btw)
Чтобы дать вам пример ожидаемого результата:
Термины: id: 1, имя: привет Модули: id: 1, содержимое: < p > Привет, мир < /p >
Я бы хотел, чтобы отображались модули с идентификатором 1, поскольку он содержит содержимое, которое где-то имеет термин «привет»
Обновлено:
Попробовал решение Пабло, но вот что происходит:
Например, «Рэй Дэвис» не имеет ничего общего с термином «Float», так что это не должно было появиться.
Ответ №1:
Я думаю, вам просто нужно изменить свое JOIN
условие на что-то вроде:
SELECT m.module_termid, t.term_name, m.module_name, m.module_content
FROM modules m
JOIN terms t ON (m.module_content LIKE '%' || t.term_name || '%')
Сказав это, это может быть потенциально очень неэффективно. Рассмотрите возможность использования ПОЛНОТЕКСТОВОГО ИНДЕКСА ВМЕСТО этой операции.
Комментарии:
1. Я думаю, что это дает декартово произведение
2. Это не полное декартово произведение. Это соединение при условии, которое будет генерировать NxM строк… И ваше условие соединения должно быть таким, каким вы хотите: все строки, в которых есть термин в
terms
таблице внутриmodule_content
.3. Вы правы, в идеале это то, что у меня было бы. Посмотрите на пример ответа, который появился (обратите внимание, что Courtesy Double Up — это термин, а <p> Ray Davis </p> — это содержимое, и это не должно было появиться, если имя термина не Ray Davis: 4 Любезно удваивайте людей, которые не понимают плавающий <p> лучДэвис.</p>
4. Я обновил описание вашим предложением и сказал, почему оно не сработало.
Ответ №2:
После небольшого исследования мое решение будет выглядеть следующим образом:
SELECT m.module_termid, t.term_name, m.module_name, m.module_content
FROM modules m
INNER JOIN terms t ON m.module_termid = t.term_id
WHERE m.module_content LIKE CONCAT('%', TRIM(t.term_name), '%')
редактировать: что касается комментария Пола Моргана, я заменил CONCAT('%', t.term_name, '%')
на CONCAT('%', TRIM(t.term_name), '%')
so, чтобы все пробелы в t.term_name были удалены. Если вам нужны пробелы в t.term_name, просто удалите TRIM
вызов и используйте старую версию ( CONCAT('%', t.term_name, '%')
)
Комментарии:
1. 1 но вам нужно обрезать t.term_name внутри CONCAT, чтобы все работало правильно. Если вы этого не сделаете, вам также потребуются любые конечные пробелы в t.term_name.
Ответ №3:
В MySQL нет оператора конкатенации, и запрос фактически должен быть записан как:
SELECT m.module_termid, t.term_name, m.module_name, m.module_content
FROM modules m
JOIN terms t ON m.module_content LIKE CONCAT('%', t.term_name, '%');
Но что произошло:
m.module_content LIKE '%' || t.term_name || '%'
фактически эквивалентно
(m.module_content LIKE '%') || (t.term_name) || ('%')
которое всегда равно 1. Таким образом, у вас есть декартово произведение =)
UPD: скорее как ссылка на меня, в MySQL есть оператор конкатенации ||
, но для его использования необходимо установить режим PIPES_AS_CONCAT:
mysql> SET sql_mode= 'pipes_as_concat';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT 'qwe' || 'asd';
----------------
| 'qwe' || 'asd' |
----------------
| qweasd |
----------------
1 row in set (0.00 sec)
Ответ №4:
Вы можете попробовать это вместо:
SELECT m.module_termid, t.term_name, m.module_name, m.module_content
FROM modules m
JOIN terms t ON (m.module_content LIKE '%' t.term_name '%')
Ответ №5:
Вместо «LIKE», использование «IN» должно быть решением: что-то вроде:-
ВЫБЕРИТЕ m.module_termid, т.term_name, м.module_name, м.module_content
ИЗ модулей m ПРИСОЕДИНИТЕ термины t К m.module_termid = т.term_id
, ГДЕ m.module_content В (ВЫБЕРИТЕ term_name ИЗ terms);
Ответ №6:
Попробуйте следующий запрос —
SELECT
tp.module_termid,
tp.term_name,
tp.module_name,
tp.module_content
FROM (
SELECT
m.module_termid,
t.term_name,
m.module_name,
m.module_content,
IF(LOCATE(t.term_name,m.module_content)!=0, m.module_content, ' ')
as required_content
FROM modules m
LEFT JOIN terms t ON m.module_termid = t.term_id
) tp
WHERE tp.required_content != '';
Для приведенного выше запроса вы получите все строки, в которых данные столбцов term_name представлены в виде целого слова в столбце module_content таблицы module_content. Если вы не хотите сопоставлять только целое слово, то в этом случае вы можете использовать функцию регулярных выражений MYSQL вместо функции LOCATE .
Документацию для функции LOCATE можно найти здесь
Ответ №7:
Я не думаю, что это хороший способ решить подобную проблему. поддерживает, что у вас много элементов модуля, а популярным словом является limit.каждый раз, когда вы выполняете sql, ему требуется много операций ввода-вывода с диска, и он может блокировать онлайн-базу данных mysql. мой способ такой:
- инвертировать индекс содержимого модуля.
- поиск популярных слов по индексу.
- привяжите идентификатор модуля к ключевому слову.
как вы можете see.it является очень эффективным и fast.so , проблема в том, как сделать инвертированный индекс для содержимого модуля.sphinx сделает хорошую работу. надеюсь, это вам поможет 🙂