Ruby on Rails - 如何连接两个表?

时间:2011-12-19 06:22:49

标签: ruby-on-rails-3 join active-relation

我在一对多关系中有两个表(主题和页面)。我想从主题和页面添加标准来解析一个sql,但进展非常缓慢,经常遇到问题。我是铁杆全新的,请帮忙。

class Subject < ActiveRecord::Base
  has_many :pages
end

class Page < ActiveRecord::Base
  belongs_to :subject 
end

主题中的样本数据,列在下面的三列:

id  name    level
1   'Math'  1
6   'Math'  2
...

页面中的示例数据,列在下面的列中:

id  name                    subject_id
--  --------------------    ----------
2   Addition                1
4   Subtraction             1
5   Simple Multiplication   6
6   Simple Division         6
7   Hard Multiplication     6
8   Hard Division           6
9   Elementary Divsion      1

鉴于我不知道subject.id,我只知道主题名称和级别,以及页面名称。这是我想要生成的sql(或者类似的东西,可以实现相同的结果):

select subjects.id, subjects.name, pages.id, pages.name from subjects, pages
 where subjects.id = pages.subject_id
   and subjects.name = 'Math'
   and subjects.level = '2'
   and pages.name like '%Division'  ;

我希望结果中有两行:

subjects.id     subjects.name   pages.id    pages.name 
-----------     -------------   --------    -----------
6               Math            6           Simple Division
6               Math            8           Hard Division

这是一个非常简单的sql,但我无法想要我想要的rails。

Here is my rails console:  

>> subject = Subject.where(:name => 'Math', :level => 2)
  Subject Load (0.4ms)  SELECT `subjects`.* FROM `subjects` WHERE `subjects`.`name` = 'Math' AND `subjects`.`level` = 2
[#<Subject id: 6, name: "Math", position: 1, visible: true, created_at: "2011-12-17 04:25:54", updated_at: "2011-12-17 04:25:54", level: 2>]
>> 
>> subject.joins(:pages).where(['pages.name LIKE ?', '%Division'])
  Subject Load (4.2ms)  SELECT `subjects`.* FROM `subjects` INNER JOIN `pages` ON `pages`.`subject_id` = `subjects`.`id` WHERE `subjects`.`name` = 'Math' AND `subjects`.`level` = 2 AND (pages.name LIKE '%Division')
[#<Subject id: 6, name: "Math", position: 1, visible: true, created_at: "2011-12-17 04:25:54", updated_at: "2011-12-17 04:25:54", level: 2>, #<Subject id: 6, name: "Math", position: 1, visible: true, created_at: "2011-12-17 04:25:54", updated_at: "2011-12-17 04:25:54", level: 2>]
>> 
>> subject.to_sql
"SELECT `subjects`.* FROM `subjects`  WHERE `subjects`.`name` = 'Math' AND `subjects`.`level` = 2"
>> subject.size
1
>> subject.class
ActiveRecord::Relation

第一个陈述:subject = Subject.where(:name =&gt;'Math',:level =&gt; 2) 第二个陈述:subject.joins(:pages).where(['pages.name LIKE?','%Division'])

问题:

  1. 链式sql的结果确实返回两​​行,但subject.size只说1?
  2. 如何告诉它从:页面返回列?
  3. 为什么subject.to_sql仍然只显示语句1中的sql,为什么它不包含语句2中的链接sql?
  4. 基本上,我需要以不同的方式编写语句来解析上面列出的sql(或者实现相同的结果)?
  5. 非常感谢。

1 个答案:

答案 0 :(得分:4)

1)ActiveRecord会将您的查询结果映射到对象而不是任意返回的行,因为您基于Subject类创建了查询,因此查看结果行并指出它只引用了1个唯一的Subject对象,因此只返回单个Subject实例。

2)列数据在那里,但是你正在反对ActiveRecord想要给你的东西,即对象。如果您希望返回页面,那么您需要在Page类上创建查询。

3)您没有保存将join(:pages)...添加回subject变量的结果。如果你这样做了:

subject = subject.joins(:pages).where(['pages.name LIKE ?', '%Division'])

运行subject.to_sql

时,您将获得完整查询

4)要获取页面对象,您可以执行类似这样的操作,请注意我们是基于Page类:

pages = Page.joins(:subject).where(['subjects.name = ? AND subjects.level = ? AND pages.name LIKE ?', 'Math', 2, '%Division'])

然后从那里访问主题名称,返回第一个Page对象:

pages[0].subject.name

因为你在第一个中有连接,所以不会导致另一个SQL查询。希望这有帮助!