Как избежать декартового произведения в запросе INNER JOIN? - PullRequest
3 голосов
/ 20 мая 2010

У меня есть 6 таблиц, назовем их a, b, c, d, e, f. Теперь я хочу найти определенное слово во всех столбцах (кроме столбцов идентификаторов) всех таблиц, скажем, «Джо». Я сделал INNER JOINS для всех таблиц, а затем использовал LIKE для поиска в столбцах.

INNER JOIN
...
ON
INNER JOIN
...
ON.......etc.
WHERE a.firstname 
~* 'Joe' 
OR a.lastname 
~* 'Joe' 
OR b.favorite_food 
~* 'Joe'
OR c.job
~* 'Joe'.......etc.

Результаты верны, я получаю все столбцы, которые искал. Но я также получаю какой-то декартово произведение, я получаю 2 или более строк с почти одинаковыми результатами.

Как мне этого избежать? Я хочу, чтобы каждая строка была только один раз, поскольку результаты должны появляться в веб-поиске.

UPDATE

Сначала я попытался выяснить, сработает ли вещь SELECT DISTINCT, используя это утверждение: pastie.org / 970959 Но оно все равно дает мне декартово произведение. Что с этим не так?

Ответы [ 5 ]

2 голосов
/ 20 мая 2010

При каких условиях вы JOIN это tables? У вас есть foreign keys или что-то?

Может быть, вам стоит найти это слово на каждом столе отдельно?

2 голосов
/ 20 мая 2010

попробуй SELECT DISTINCT?

1 голос
/ 20 мая 2010

Какой сервер вы используете? Microsoft SQL Server имеет функцию полнотекстового индекса (я думаю, что у других тоже есть что-то подобное), которая позволяет искать ключевые слова гораздо менее ресурсоемким способом.

Также рассмотрите возможность использования UNION вместо объединения таблиц.

0 голосов
/ 20 мая 2010

Если ваши таблицы являются таблицами типов сущностей, например, a являются лицами, а b являются компаниями, я не думаю, что вы можете избежать декартового произведения, если будете искать результаты в этом способ (одиночный запрос).

Вы говорите, что хотите найти во всех таблицах определенное слово, но, вероятно, хотите разделить результаты на соответствующие типы. Правильно? В противном случае поиск в Интернете не будет иметь большого смысла. Поэтому, если вы ищите «Джо», вы захотите увидеть людей с именем «Джо» и, например, компанию «Джо». Поскольку вы ищете разные объекты, вы должны разделить поиск по разным запросам.

Если вы действительно хотите сделать это в одном запросе, вам придется изменить структуру базы данных, чтобы приспособить ее. Вам понадобится некоторая форма «таблицы поиска», содержащая идентификатор сущности (PK) и тип сущности, а также список ключевых слов, по которым вы хотите найти эту сущность. Например:

EntityType, EntityID, Keywords
------------------------------
Person,     4,        'Joe', 'Doe'
Company,    12,       'Joe''s Gym', 'Gym'

Что-то подобное?

Однако отличается, когда ваш поиск возвращает только один тип сущности, скажем Person, и вы хотите вернуть Person, для которых вы получили совпадение по этому ключевому слову (в любой связанной таблице с этим Person ). Затем вам нужно будет выбрать все поля, которые вы хотите показать, и сгруппировать их, оставляя поля, в которых вы ищете. Включение их неизбежно приводит к декартовому произведению.

Кстати, я тут просто мозговой штурм. Надеюсь, что это полезно.

0 голосов
/ 20 мая 2010

Не видя ваших таблиц, я могу только предположить, что здесь происходит то, что у вас где-то есть отношения один-ко-многим. Вы, вероятно, хотите сделать все в подзапросе, выбрать отдельные идентификаторы, а затем получить данные, которые вы хотите отобразить по идентификатору. Что-то вроде:

SELECT a.*, b.*
FROM (SELECT DISTINCT a.ID
      FROM ...
      INNER JOIN ...
      INNER JOIN ...
      WHERE ...) x
INNER JOIN a ON x.ID = a.ID
INNER JOIN b ON x.ID = b.ID

Однако следует отметить пару вещей:

  • Это будет sloooow , и вы, вероятно, вместо этого захотите использовать полнотекстовый поиск (если ваша СУБД это поддерживает).

  • Может быть быстрее искать каждую таблицу отдельно, чем сначала объединять все в декартовом произведении, а затем фильтровать с помощью OR.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...