5

I'm desperately trying to make sense of Arel, mostly because I hate dealing with SQL; I was doing so well, but I've hit a wall.

I've been working in Rails 3.0.0, and I'm trying to make a complex query with some math in it. The real case is rather more complex, but I've simplified a bit. In my example, I have a table with a particular string field, and I want a count of all the records, as well as a count for each of two possible values of that field, grouped by a foreign id.

Under Rails 3.0.0, I can do this (console commands):

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

and at this point I can do do x.to_sql and... well, I'm not entirely sure it's right, but the results look right, aside from having the foreign_id column twice.

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`

So far so good. However, when I try to join in a second set of counts like this:

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

it just hangs up, leading me to think I'm hitting this bug

(btw I've got more counts to add in, and ideally 'some_thingies' should itself be an arel object representing more filtering on which thingies we're counting... but I digress...)

So, I decided to try out the latest edge Arel and Rails, and bumped up my gems accordingly:

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'

and now when I try to do do the first join, it fails miserably:

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

This doesn't seem like a bug in Arel - if anything, it seems more like the fact that it worked before is the bug. I think I just don't know what an Arel::SelectManager is and what to do with it. It seemed like I was doing so well, but I really don't get what is going on.

Do I need to somehow make a new table based on the SelectManager I've got? Or am doing something wrong in my configuration which makes the [] syntax fail? Or do I just totally fail to understand what Arel does? I still don't quite get what I'm supposed to do with Arel::Rows, but I suppose I'll get the hang of that; and I suspect I can get rid of the extra foreign key in the results with a project()...

But I'm still pretty lost. Haaaaalp!

p.s. does 'railties' rhyme with 'frailties,' or with 'mail guys'?

4

2 回答 2

4

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

我使用 Arel 的方式的问题 1 是您只能加入新制作的桌子。那是无关紧要的。

真正的问题是我试图计算两个不同的东西。我真的应该按外国 ID 和“some_field”分组。我只是不知道你能做到这一点,结果有点奇怪。如果我不关心 some_field 的所有可能值,这可能会很烦人,但我确实关心它们,而且我可以很容易地将它们相加得到总数,而且现在很容易将它们过滤掉。

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

哦!道德:SQL 只知道行。时期。

于 2010-10-16T08:53:30.287 回答
3

Arel 已经彻底重做。这项倡议是由嫩爱 (Aaron) 发起的。在很大程度上组成的查询中存在性能问题。

我什至自己也为这项新倡议做出了贡献。

Arel 现在使用抽象语法树(在选择管理器中)和访问者模式。

您不妨放弃 Arel 1.0.1 为 2.0.0 提供风味的方式(在前往 3.0.x 以与导轨对齐的路上)

于 2010-11-04T10:12:44.077 回答