SELECT with OR including tables

I have a database with three tables: books (with details about the book, PK is the CopyID), keywords (list of keywords, PK is the id), and KeywordsLink, which is a table of links of many of the many books and keywords with Field IDs, BookID and KeywordID.

I am trying to create an advanced search form in my application where you can search by various criteria. At the moment I have a job with Title, Author and Publisher (all from the Book table). It creates SQL as:

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

      

I want to expand this search as well as search with tags - mainly to add another OR clause to search for tags. I tried to do it by doing the following

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

      

I thought that using parentheses might separate the 2nd part from my kinda sentence, so joining was only appreciated in that part, but it looks like it doesn't. This all gives me a long list of multiple copies of the same book that suits a bit Title LIKE '%Joel%'

.

Is there a way to do this using pure SQL or will I have to use two SQL statements and combine them in my application (remove duplicates in the process).

I'm using MySQL at the moment if it matters, but the application is using ODBC and I'm hoping to make it DB agnostic (maybe even use SQLite eventually, or have it so the user can choose which DB to use).

0


source to share


7 replies


What you did here made a Cartesian result set by linking tables with commas but not having any join criteria. Switch your statements to use external join operators and that should allow you to reference keywords. I don't know your schematic, but maybe something like this will work:



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

      

+3


source


You need to join 3 tables together, which gives you a tabular result set. Then you can check any columns you like and make sure you get great results (i.e. no duplicates).

Like this:

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

      



You should also try to avoid triggering LIKE values ​​with a percent sign (%), as this means SQL Server cannot use an index on that column and must perform a full (and slow) scan of the table. It starts making the request in the "starts with" request.

Perhaps also consider the options for full text search in SQL Server.

+7


source


Use UNION

.

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

      

The point is that you can write two (or more) simple and efficient queries instead of one complex query that tries to do everything at once.

If the number of resulting rows is small, then there UNION

will be very little overhead (and you can use the faster UNION ALL

one if you don't have duplicates or don't care).

+3


source


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%'))

      

Beware that older MySQL versions didn't like subqueries. I think they fixed it.

+1


source


You should also restrict the product of the connection by specifying something like

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

But I don't know your exact data model, so your solution might be slightly different.

0


source


I don't know how a "conditional join" can be done in SQL. I think your best bet would be to execute the two statements separately and combine them in an application. This approach is also more likely to remain DB agnostic.

0


source


It looks like Neil Barnwell has considered the answer I would give, but I'll add one thing ...

Books can have more than one author. If your data model is indeed designed, as your query implies, you might want to consider changing it to accommodate that fact.

0


source







All Articles