【问题标题】:What just happened to Arel and what do I do with an Arel::SelectManager?Arel 刚刚发生了什么,我该如何处理 Arel::SelectManager?
【发布时间】:2011-04-25 22:26:23
【问题描述】:

我拼命想理解 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 对象,表示对我们正在计数的事物进行更多过滤......但我离题了......)

所以,我决定尝试最新的 edge 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'

现在当我尝试进行 first 加入时,它惨遭失败:

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() 去掉结果中多余的外键...

但我还是很迷茫。哈哈!

附言'railties' 是否与 'frailties' 或 'mail guy' 押韵?

【问题讨论】:

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


    【解决方案1】:

    我将回答我自己的问题,因为似乎没有人感兴趣,现在我知道自己做错了什么,如果我理解 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 只知道行。期间。

    【讨论】:

    • 我也得到了一个 SelectManager,但我不知道如何处理它。你的这个答案没有回答这个问题。无论如何,如果你认为你给自己的答案是正确答案,你应该标记为“正确答案”。
    • 是的,我真的没有正确的答案。我想我真正要问的是“有人可以告诉我如何以实用的方式使用 Arel。”我已经放弃了,我使用 Squeel github.com/ernie/squeel 获得了非常好的结果
    • 嗯...只是我的意见:我猜你并没有太努力。我从未在 arel 中使用过 group 子句,不过,我越来越乐于使用它。
    • 为了在 arel 中工作的例子:users=User.arel_table;角色=角色.arel_table; User.joins(:roles).where(roles[:name].eq("admin").and(user[id].gt(50))); cmets=评论.arel_table; Post.joins(:cmets).order(cmets[:id].count)
    【解决方案2】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2012-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 2012-01-17
      相关资源
      最近更新 更多