2008-11-21 1 views
0

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

Я пытаюсь создать расширенную форму поиска в своем приложении, где вы можете искать по различным критериям. На данный момент у меня есть работа с Title, Author и Publisher (все из таблицы Book). Он производит 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, и я надеюсь сделать его агностиком DB (возможно, даже в конечном итоге использовать SQLite или иметь его, чтобы пользователь мог выбрать, какую БД использовать) ,

ответ

3

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

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
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

Я не уверен, что под-суб-выбор здесь является наиболее эффективным способом приблизиться к этому. Я определенно проведу сравнение на этом, чтобы увидеть, будет ли он медленным. – 2008-11-21 19:49:29

+0

Это позволяет избежать использования ключевых слов и ключевых слов для тех, которые вы не указали по ключевому слову. Я думаю, что это будет победа. – 2008-11-21 19:51:13

7

Вам необходимо присоединиться к 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.

+0

Или варианты полного поиска текста в MySQL, также! :) – 2008-11-21 20:14:15

+0

Необходимо будет исследовать, могут ли все используемые мной БД иметь параметры полного текстового поиска, и если да, если все они работают одинаково. – robintw 2008-11-21 20:15:18

+0

Кроме того, не уверен в проблемах с использованием знака% - я хочу соответствовать вещам где угодно в поле - и я думал, что вам нужно использовать знаки% в заявлениях LIKE - это не так? – robintw 2008-11-21 20:16:14

0

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

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

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

3

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

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

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

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

0

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

0

Похоже, Нил Barnwell накрыла ответ, что я дал бы, но я добавлю одну вещь ...

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

Смежные вопросы