Я хочу найти все строки, содержащие определенные слова в таблице SQL Server.
Допустим, моя таблица называется TableA и имеет следующую структуру:
ID State Description
1 LA Good quality products
2 NY Race diversity
3 WA We are too diverse a group
4 LA Environmental problem
5 LA Good environment
У меня также есть другая таблица с именем TableB, в которой есть список слов, которые я хочу найти:
Word
good quality
divers
environment
Что я хочу сделать, так это получить все строки из таблицы A, которые содержат любое из слов в таблице B, а также конкретные ключевые слова, найденные в каждой строке, например:
ID State Description keywords
1 LA Good quality products good quality
2 NY Race diversity and environmentally friendly diversity, environmental
3 WA We are too diverse a group diverse
4 LA Environmental problem Environmental
5 LA Good environment, good quality environment, good quality
Я мог бы использовать '%divers%'
, если бы данных не было в таблице, но поскольку это так, мне нужно искать слова в таблице.
Я мог бы также использовать «дайвер%», но это может пропустить такие слова, как «разнообразие воздуха», которые я хочу включить.
Если я сделаю '% divers %', может ли он захватить все описания, содержащие это слово, вместо каждого слова?
Для точных совпадений я использовал следующий запрос:
SELECT ID, State,
Description, String_Agg(v.Keywords, ', ') AS Keywords
FROM TableA as A
outer apply (
select (Trim(value)) t,
case when exists
(select * from tableB as B where lower(B.Word)=lower(Trim(value)))
then Trim(value) end Keywords
from String_Split(Description, ' ')
)v
where Keywords is not null
group by A.ID, A.State, A.Description
Однако я также хочу искать похожие ключевые слова, а не только точные совпадения. Есть ли способ сделать это в SQL Server? Если нет, есть ли аналогичный подход, который я мог бы попробовать?
Что означает «Я мог бы использовать %divers%, если бы данных не было в таблице»? Вы можете выполнять like
запросы с подстановочными знаками, даже если данные находятся в таблице (хотя я не уверен, что понимаю ваши требования достаточно, чтобы рекомендовать это).
Во-первых, я думаю, что другой ответ полнотекстового поиска предпочтительнее, если он соответствует вашим целям. Однако...
Я думаю, вы могли бы использовать что-то вроде следующего, чтобы получить ожидаемый результат (вы можете дважды проверить пограничные случаи, чтобы убедиться, что я ничего не пропустил в индексах):
WITH cte AS
(
SELECT id, state, description, word, CHARINDEX(lower(word), lower(description)) pi
FROM TableA INNER JOIN TableB
ON CHARINDEX(lower(word), description) > 0
)
, cte2 AS
(
SELECT cte.*, CHARINDEX(' ', reverse(substring(description, 1, pi))) ps, CHARINDEX(' ', description, pi+len(word)) ns
FROM cte
)
SELECT id, state, description, STRING_AGG(substring(description, pi - CASE ps WHEN 0 THEN 0 ELSE ps-2 END, CASE ns WHEN 0 THEN len(description) ELSE ns - (pi - CASE ps WHEN 0 THEN 0 ELSE ps-2 END) END), ',')
FROM cte2
GROUP BY id, state, description
Вы можете увидеть, как это работает в этой скрипте.
Идея состоит в том, что первое CTE находит все строки, в которых есть совпадения, и индекс, в котором происходит совпадение. Затем второй CTE находит предыдущий пробел (до совпадения) как ps
и новый пробел (после совпадения) как ns
). Основной запрос отделяет слова. Нет необходимости использовать CTE, но мне было проще смоделировать. Независимо от того, используете ли вы CTE или нет, вы, вероятно, могли бы немного почистить это.
select id, state, description, string_agg( keyword, ', ') as Keywords
from (
select distinct id, state, description,
case when lower(Trim(value)) like '%'+lower(word)+'%' then trim(value)
when word like '% %'
then substring(description,
charindex(lower(word), lower(description)),
len(word))
end keyword
from tablea cross apply string_split(description, ' ')
join tableb b on description like '%'+word+'%') v
group by id, state, description
Это решение похоже на ваше, за исключением слов в таблице B, содержащих пробелы, которые требуют специальной обработки.
Спасибо за вашу помощь, и извините за поздний ответ. Это очень похоже на то, что я ищу. Если я ищу 5-ю строку моего идеального результата. В нем есть дополнительная запятая, например, «окружающая среда, хорошее качество». Как мне избавиться от него?
Потому что environment,
рассматривается как целое слово. Вы можете удалить эти запятые с помощью replace
либо на входе, либо на выходе, как в dbfiddle.
Использование
string_split()
означает, что вы сравниваете только отдельные слова и поэтому не найдете фразы в своих ключевых словах, таких какgood quality
.