Arel发生了什么事,我怎么处理Arel :: SelectManager?

时间:2010-10-15 12:49:41

标签: sql ruby-on-rails-3 arel

我拼命想弄清楚Arel,主要是因为我讨厌处理SQL;我做得很好,但是我已经撞墙了。

我一直在使用Rails 3.0.0,我正在尝试使用一些数学函数进行复杂的查询。真实情况相当复杂,但我简化了一下。在我的示例中,我有一个带有特定字符串字段的表,我想要计算所有记录,以及该字段的两个可能值中的每一个的计数,按外来ID分组。

在Rails 3.0.0下,我可以这样做(控制台命令):

t = Arel::Table.new(:some_thingies)
e = t                                  .project(t[:foreign_id], t[:foreign_id].count.as('all_count'))  .group(t[:foreign_id])
c = t.where(t[:some_field].eq('type1')).project(t[:foreign_id], t[:foreign_id].count.as('type1_count')).group(t[:foreign_id])
x = e  
x = x.join(c).on(e[:foreign_id].eq(c[:foreign_id])) 

此时我可以做x.to_sql而且......好吧,我不完全确定它是对的,但结果看起来是正确的,除了两次使用foreign_id列。

SELECT     
  `some_thingies_external`.`foreign_id`, 
  `some_thingies_external`.`all_count`, 
  `some_thingies_external_2`.`foreign_id`, 
  `some_thingies_external_2`.`type1_count` 
FROM       
  (SELECT     
    `some_thingies`.`foreign_id`, COUNT(`some_thingies`.`foreign_id`) 
   AS `type1+count` 
   FROM       `some_thingies`  
   GROUP BY  `some_thingies`.`foreign_id`) `some_thingies_external`  
INNER JOIN 
  (SELECT     `some_thingies`.`foreign_id`, COUNT(`some_thingies`.`foreign_id`) 
   AS `type1_count` 
   FROM       `some_thingies`  
   WHERE     `some_thingies`.`type` = 'type1' 
   GROUP BY  `some_thingies`.`foreign_id`) `some_thingies_external_2` 
ON `some_thingies_external`.`foreign_id` = `some_thingies_external_2`.`foreign_id`

到目前为止一切顺利。但是,当我尝试加入第二组这样的计数时:

i = t.where(t[:some_field].eq('type2')).project(t[:foreign_id], t[:foreign_id].count.as('type2_count')).group(t[:foreign_id])
x = x.join(i).on(e[:foreign_id].eq(i[:foreign_id]))

它只是挂断了,让我觉得我正在点击this bug

(顺便说一句,我有更多的计数要加入,理想情况下'some_thingies'应​​该是一个arel对象,代表更多过滤我们正在计算的东西......但我离题了......)

所以,我决定尝试最新的Arel和Rails边缘,并相应地提升我的宝石:

gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'rack', :git => 'git://github.com/rack/rack.git'
gem 'arel', :git => 'http://github.com/brynary/arel.git'

现在当我尝试做第一次加入时,它失败了:

ruby-1.9.2-preview3 >     x = x.join(c).on(e[:foreign_id].eq(c[:foreign_id])) 
NoMethodError: undefined method `[]' for #<Arel::SelectManager:0x00000104311e38>
    from (irb):12
    from /Users/stephan/.rvm/gems/ruby-1.9.2-preview3/bundler/gems/rails-c42ea2172eb9/railties/lib/rails/commands/console.rb:44:in `start'
    from /Users/stephan/.rvm/gems/ruby-1.9.2-preview3/bundler/gems/rails-c42ea2172eb9/railties/lib/rails/commands/console.rb:8:in `start'
    from /Users/stephan/.rvm/gems/ruby-1.9.2-preview3/bundler/gems/rails-c42ea2172eb9/railties/lib/rails/commands.rb:33:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

这似乎不是Arel中的一个错误 - 如果有的话,它似乎更像是它以前工作的事实是错误。我想我只是不知道Arel :: SelectManager是什么以及如何处理它。看起来我做得很好,但我真的不知道发生了什么。

我是否需要以某种方式根据我得到的SelectManager创建一个新表?或者我在配置中做错了什么导致[]语法失败?或者我完全不理解Arel的作用?我仍然不太了解我应该用Arel :: Rows做什么,但我想我会得到那个;我怀疑我可以通过project()...

来删除结果中的额外外键

但我还是很迷茫。 Haaaaalp!

P.S。用“弱点”或“邮件人”做“铁路”押韵吗?

2 个答案:

答案 0 :(得分:3)

我将回答我自己的问题,因为似乎没有人感兴趣,现在我知道我做错了什么,我可以看到,如果我理解SQL,那将是显而易见的。

问题1与我使用Arel的方式是你只能加入一个新制作的表。那就是重点。

真正的问题是我试图计算两件不同的事情。我真的应该通过外国ID和'some_field'进行分组。我只是不知道你能做到这一点,它的结果有点奇怪。如果我不关心some_field的所有可能值,这可能很烦人,但我确实关心它们,并且我可以轻松地将它们添加到足以得到总数,并且现在很容易将它们过滤掉。 / p>

t = Arel::Table.new(:some_thingies)    
e = t.group(:foreign_id, :some_field).project(t[:id], t[:foreign_id], t[:some_field])

一旦我弄清楚了,我想出了如何使用普通的ActiveRecord而不是ARel:

SomeThing.group('foreign_id, some_field').select('id, foreign_id, some_field, count(1)')

D'哦!道德:SQL只知道行。周期。

答案 1 :(得分:3)

Arel已经从内心完全重做。这项计划是由招标(Aaron)启动的。在大量撰写的查询中存在性能问题。

我自己甚至为这项新计划做出了贡献。

Arel现在使用抽象语法树(在Select Manager中)和访问者模式。

你可能会废弃Arel 1.0.1在2.0.0版本中工作的方式(在3.0.x的路上与rails对齐)