Как получить совпадающее имя столбца при поиске по нескольким столбцам в PostgreSQL?

#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. Спасибо, что открыли мне глаза на все вышесказанное, действительно оценили!