5

私は必死に Arel を理解しようとしていますが、それは主に SQL を扱うのが嫌いだからです。よくやったけど、壁にぶち当たった。

私はRails 3.0.0で作業しており、数学を含む複雑なクエリを作成しようとしています. 実際のケースはかなり複雑ですが、少し単純化しました。私の例では、特定の文字列フィールドを持つテーブルがあり、すべてのレコードの数と、外部 ID でグループ化されたそのフィールドの 2 つの可能な値のそれぞれの数が必要です。

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 列が 2 回あることを除けば、結果は正しく見えます。

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`

ここまでは順調ですね。ただし、次のようなカウントの 2 番目のセットに参加しようとすると、次のようになります。

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

ハングアップするだけで、このバグにぶつかっていると思います

(ちなみに、追加するカウントがさらにあります。理想的には、「some_thingies」自体が、カウントしているモノに対するより多くのフィルタリングを表すアレルオブジェクトであるべきです...しかし、私は脱線します...)

そこで、最新のエッジである Arel と Rails を試すことにし、それに応じて gem を増やしました。

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::Rows で何をすべきかをよく理解していませんが、コツはつかめると思います。project() を使用すると、結果から余分な外部キーを取り除くことができると思います...

しかし、私はまだかなり迷っています。はぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁ!

ps 'railties' は 'frailties' または 'mail guy' と韻を踏んでいますか?

4

2 に答える 2

4

誰も興味を持っていないように見えるので、私は自分の質問に答えるつもりです。そして、私が間違っていることを知ったので、SQL を理解していればそれは明らかであることがわかります。

私が Arel を使っていた問題点 1 は、作成したばかりのテーブルにしか参加できないことです。それは論外です。

本当の問題は、私が 2 つの異なるものを数えようとしていることです。私は本当に外部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 は根性から完全に作り直されました。このイニシアチブは、tenderlove (Aaron) によって開始されました。大部分が構成されたクエリでパフォーマンスの問題が発生しました。

私自身も、この新しいイニシアチブに貢献しました。

Arel は、Abstract Syntax Tree (Select Manager 内) と Visitor パターンを使用するようになりました。

Arel 1.0.1 が 2.0.0 のフレーバーで動作する方法を破棄することもできます (レールに合わせて 3.0.x に移行する途中)。

于 2010-11-04T10:12:44.077 に答える