ВЫБЕРИТЕ с ИЛИ, включая объединения таблиц - PullRequest
0 голосов
/ 21 ноября 2008

У меня есть база данных с тремя таблицами: Книги (с деталями книги, PK - это CopyID), Ключевые слова (список ключевых слов, PK - это идентификатор) и KeywordsLink, которая представляет собой таблицу ссылок «многие-многие» между книгами и ключевыми словами с ID полей, BookID и KeywordID.

Я пытаюсь создать в своем приложении форму расширенного поиска, в которой вы можете выполнять поиск по различным критериям. На данный момент у меня это работает с названием, автором и издателем (все из таблицы книги). Он производит SQL как:

SELECT * FROM Books WHERE Title Like '%Software%' OR Author LIKE '%Spolsky%';

Я хочу расширить этот поиск, чтобы также выполнять поиск по тегам - в основном, чтобы добавить еще одно предложение ИЛИ для поиска по тегам. Я попытался сделать это, выполнив следующее

SELECT *
    FROM Books, Keywords, Keywordslink
    WHERE Title LIKE '%Joel%'
       OR (Name LIKE '%good%' AND BookID=Books.CopyID AND KeywordID=Keywords.ID)

Я думал, что использование скобок может разделить 2-ю часть на свое собственное своеобразное предложение, поэтому объединение оценивалось только в этой части - но, похоже, это не так. Все, что он дает мне, это длинный список нескольких экземпляров одной книги, которая удовлетворяет биту Title LIKE '%Joel%'.

Есть ли способ сделать это, используя чистый SQL, или мне придется использовать два оператора SQL и объединить их в моем приложении (удаляя дубликаты в процессе).

В данный момент я использую MySQL, если это имеет значение, но приложение использует ODBC, и я надеюсь сделать его независимым от БД (возможно, в конечном итоге даже использовать SQLite или использовать его, чтобы пользователь мог выбрать, какую БД использовать).

Ответы [ 7 ]

7 голосов
/ 21 ноября 2008

Вам нужно объединить 3 таблицы вместе, что даст вам табличный набор результатов. Затем вы можете проверить любые столбцы, которые вам нравятся, и убедиться, что вы получите отличные результаты (т.е. без дубликатов).

Как это:

select distinct b.*
from books b
left join keywordslink kl on kl.bookid = b.bookid
left join keywords k on kl.keywordid = k.keywordid
where b.title like '%assd%'
or k.keyword like '%asdsad%'

Вам также следует избегать запуска значений LIKE со знака процента (%), поскольку это означает, что SQL Server не может использовать индекс для этого столбца и должен выполнять полное (и медленное) сканирование таблицы. Это начинает превращать ваш запрос в запрос «начинается с».

Может быть, рассмотрим также опции полнотекстового поиска в SQL Server.

3 голосов
/ 21 ноября 2008

Использование UNION.

(SELECT Books.* FROM <first kind of search>)
UNION
(SELECT Books.* FROM <second kind of search>)

Дело в том, что вы можете написать два (или более) простых и эффективных запросов вместо одного сложного запроса, который пытается сделать все сразу.

Если число результирующих строк невелико, тогда UNION будет иметь очень небольшие накладные расходы (и вы можете использовать быстрее UNION ALL, если у вас нет дубликатов или их не волнует).

3 голосов
/ 21 ноября 2008

То, что вы сделали здесь, - это декартово множество результатов, объединив таблицы с запятыми, но не имея критериев соединения. Переключите ваши операторы, чтобы использовать внешние операторы соединения, и это должно позволить вам ссылаться на ключевые слова. Я не знаю вашу схему, но, возможно, что-то подобное сработает:

SELECT 
  * 
FROM 
  Books 
  LEFT OUTER JOIN KeywordsLink ON KeywordsLink.BookID = Books.CopyID 
  LEFT OUTER JOIN Keywords ON Keywords.ID = KeywordsLink.KeywordID 
WHERE Books.Title LIKE '%JOEL%' 
      OR Keywords.Name LIKE '%GOOD%'
1 голос
/ 21 ноября 2008
SELECT * FROM books WHERE title LIKE'%Joel%' OR bookid IN 
         (SELECT bookid FROM keywordslink WHERE keywordid IN
         (SELECT id FROM keywords WHERE name LIKE '%good%'))

Остерегайтесь того, что более старые версии MySQL не любили подселекты. Я думаю, что они это исправили.

0 голосов
/ 22 ноября 2008

Похоже, Нейл Барнвелл раскрыл ответ, который я бы дал, но я добавлю одну вещь ...

Книги могут иметь более одного автора. Если ваша модель данных действительно разработана так, как предполагает ваш запрос, возможно, вы захотите изменить ее, чтобы учесть этот факт.

0 голосов
/ 21 ноября 2008

Я не знаю ни одного способа выполнения «условного соединения» в SQL. Я думаю, вам лучше всего выполнить два утверждения по отдельности и объединить их в приложении. Этот подход также с большей вероятностью останется независимым от БД.

0 голосов
/ 21 ноября 2008

Вы также должны ограничить продукт объединения, указав что-то вроде

Books.FK1 = Keywords.FK1 and
Books.FK2 = Keywordslink.FK2 and
Keywords.FK3 = Keywordslink.FK3

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

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