Let's say I have this data (notice the null author_id
in third book):
Authors
-------------------------
id | name
-------------------------
1 | Susan Collins
2 | Steven Meyer
-------------------------
Books
--------------------------------------
id | author_id | title
--------------------------------------
1 | 1 | Hunger Games
2 | 2 | Twilight
3 | nil | Games of Throne
--------------------------------------
I have a search bar for Books. I want it to be searchable by Book's title and Author's name.
For example when I search for "Susan". It will return books are titled like "Susan" or authored by name like "Susan".
The problem is: When I search for "Game", it only returns "Hunger Games". It doesn't select "Game of Throne" because the author_id
is null.
I made the SQLFiddle here.
This is the SQL generated from my Rails code:
SELECT books.* FROM books
INNER JOIN authors ON authors.id = books.author_id
WHERE (
( LOWER(books.title) LIKE LOWER("%game%") )
OR
( LOWER(authors.name) LIKE LOWER("%game%") )
)
And the result only returns 1 row: "Hunger Games". No "Game of Thrones".
Is there a way to include the row with null Foreign Key?
I will accept SQL query as answer, I will try to figure out the Rails code myself.
Thanks
[EDIT]
Here's the Rails code that generate the SQL: (I use Squeel gem)
search = "%#{params[:search]}%" # the query is taken from param
Books.joins(:author).where {
( lower(title) =~ lower(search) ) |
( lower(author.name) =~ lower(search) )
}
What you want is a LEFT JOIN
instead of an INNER JOIN
:
http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
Replace left by inner in your Sql Fiddle and you will get the books with and without authors.
In rails you can have a left join by replacing joins
by includes
. Because it keeps data from the first table without relations, it is often used when you want to eager load relations to prevent the N+1 query problem.