#postgresql #subquery #full-text-search #inner-join
#postgresql #подзапрос #полнотекстовый поиск #внутреннее соединение
Вопрос:
Есть ли способ получить совпадающее имя столбца при поиске по нескольким столбцам в PostgreSQL?
Допустим, у меня есть следующая структура таблицы и запрос:
CREATE TABLE document (
id serial PRIMARY KEY,
document_content VARCHAR
);
CREATE TABLE story (
id serial PRIMARY KEY,
headline VARCHAR
);
-----
SELECT
"document".*,
story.id,
story.headline
FROM
"document"
INNER JOIN story_document AS Documents_join ON "document".id = Documents_join.document_id
INNER JOIN story ON "story".id = Documents_join.story_id
WHERE to_tsvector(document_content) @@ to_tsquery('foo')
OR to_tsvector(headline) @@ to_tsquery('foo');
Я думал о том, чтобы объединить значения двух столбцов, запустить полнотекстовый поиск, затем создать подзапрос для обоих столбцов и повторно выполнить поиск по отдельности и записать результат в качестве ссылки, но это означало бы выполнение поиска 3 раза:
SELECT
"document".*,
story.id AS story_id,
story.headline
(SELECT "document".id WHERE to_tsvector(document_content) @@ to_tsquery('foo')) AS "matching_document_id",
(SELECT story_id WHERE to_tsvector(headline) @@ to_tsquery('foo')) AS "matching_story_id"
FROM
"document"
INNER JOIN story_document AS Documents_join ON "document".id = Documents_join.document_id
RIGHT JOIN story ON "story".id = Documents_join.story_id
WHERE to_tsvector(document_content || ' ' || headline) @@ to_tsquery('foo');
Как я могу получить ссылку на столбец: document_content или заголовок, где ключевое слово «foo» было найдено в одном запросе?
Спасибо!
Комментарии:
1. Извините, я обновил вопрос.
2. На самом деле к тому времени, когда они будут объединены, это не должно иметь значения, в любом случае.
3. Это имеет большое значение.
4. Вы вызываете у меня любопытство! : D
Ответ №1:
Поскольку столбцы находятся в разных таблицах, лучшее, что вы можете сделать, это перевести OR
в UNION
:
SELECT
"document".*,
story.id,
story.headline
FROM
"document"
INNER JOIN story_document AS Documents_join ON "document".id = Documents_join.document_id
INNER JOIN story ON "story".id = Documents_join.story_id
WHERE to_tsvector(document_content) @@ to_tsquery('foo')
UNION
SELECT
"document".*,
story.id,
story.headline
FROM
"document"
INNER JOIN story_document AS Documents_join ON "document".id = Documents_join.document_id
INNER JOIN story ON "story".id = Documents_join.story_id
WHERE to_tsvector(headline) @@ to_tsquery('foo');
Тогда PostgreSQL не нужно создавать полное соединение, чтобы отфильтровать большинство строк. Мой вариант будет быстрым, если условия являются выборочными и индексированными, а также у вас есть индексы для условий соединения, чтобы вы могли получать быстрые соединения с вложенным циклом.
Вот еще кое-что о работе OR
.
Комментарии:
1. Спасибо, честно говоря, я не знал о UNION, прочитаю об этом, однако до сих пор не ясно, какой столбец был источником совпадения:
document_content
илиheadline
. Дело в том, что на стороне клиента я должен отображать ссылку на тот или иной.2. Я обновил свой вопрос своим наивным подходом — возможно, это помогает понять, чего я хотел бы достичь, это работает, но совсем не оптимально.
3. Тривиально: добавьте оба
@@
выражения в список результатов, тогда вы получите два логических выражения, которые сообщают вам, что соответствует.4. Спасибо, что открыли мне глаза на все вышесказанное, действительно оценили!