0

假设我有这些数据(注意author_id第三本书中的空值):

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

我有一个书籍搜索栏。我希望它可以通过书名和作者姓名进行搜索。

例如,当我搜索“Susan”时。它将返回标题为“Susan”或作者姓名为“Susan”的书籍。

问题是:当我搜索“游戏”时,它只返回“饥饿游戏”。它没有选择“权力的游戏”,因为它author_id是空的。

我在这里制作了SQLFiddle

这是从我的 Rails 代码生成的 SQL:

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

结果只返回 1行:“饥饿游戏”。没有《权力的游戏》。

有没有办法包含具有空外键的行?

我将接受 SQL 查询作为答案,我将尝试自己找出 Rails 代码。

谢谢

[编辑]

这是生成 SQL 的 Rails 代码:(我使用Squeel gem)

search = "%#{params[:search]}%" # the query is taken from param

Books.joins(:author).where {
  ( lower(title) =~ lower(search) ) |
  ( lower(author.name) =~ lower(search) )
}
4

2 回答 2

6

你想要的是一个LEFT JOIN而不是一个INNER JOIN: http: //blog.codinghorror.com/a-visual-explanation-of-sql-joins/

在您的 Sql Fiddle 中将 left 替换为 inner,您将获得有作者和没有作者的书籍。

在 Rails 中,您可以通过替换joins来进行左连接includes。因为它保留第一个表中的数据而没有关系,所以当您想要预先加载关系以防止 N+1 查询问题时,通常会使用它。

于 2014-11-04T10:15:17.487 回答
0

也许这就是你所追求的......

SELECT b.* 
  FROM books b
  LEFT
  JOIN authors a
    ON a.id = b.author_id
   AND a.name LIKE '%game%'
 WHERE b.title LIKE '%game%';
于 2014-11-04T10:17:28.507 回答