Что только что произошло с Arel и что мне делать с Arel::SelectManager?

Я отчаянно пытаюсь разобраться в Arel, главным образом потому, что ненавижу иметь дело с SQL; У меня все было хорошо, но я уперся в стену.

Я работаю в Rails 3.0.0 и пытаюсь сделать сложный запрос с некоторой математикой. Реальный случай несколько сложнее, но я немного упростил. В моем примере у меня есть таблица с определенным строковым полем, и мне нужно количество всех записей, а также количество для каждого из двух возможных значений этого поля, сгруппированных по внешнему идентификатору.

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

он просто зависает, заставляя меня думать, что я сталкиваюсь с этой ошибкой

(кстати, у меня есть больше счетчиков, которые нужно добавить, и в идеале '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::Rows, но я полагаю, что разберусь с этим; и я подозреваю, что могу избавиться от лишнего внешнего ключа в результатах с помощью проекта()...

Но я все еще довольно потерян. Хааааалп!

p.s. рифмуется ли слово «railties» со словом «failties» или с «почтальонами»?


person stephan.com    schedule 15.10.2010    source источник


Ответы (2)


Я собираюсь ответить на свой вопрос, так как никто не заинтересован, и теперь, когда я знаю, что я делаю неправильно, я вижу, что это было бы очевидно, если бы я понимал SQL.

Проблема 1 с тем, как я использовал Arel, заключается в том, что вы можете присоединиться только к свежеприготовленному столу. Это не относится к делу.

Настоящая проблема в том, что я пытаюсь сосчитать две разные вещи. Я действительно должен группировать по внешнему идентификатору И «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 знает только о строках. Период.

person stephan.com    schedule 16.10.2010
comment
Я также получаю SelectManager, и я не знаю, что с ним делать. Этот ваш ответ не отвечает на этот вопрос. В любом случае, если вы считаете, что ответ, который вы даете себе, является правильным ответом, вам, возможно, следует отметить его как правильный ответ. - person Pedro Rolo; 20.07.2011
comment
да, у меня действительно нет правильного ответа. Я думаю, что я действительно спрашивал, может ли кто-нибудь показать мне, как использовать Arel на практике. Я отказался от этого и получаю очень хорошие результаты со Squeel github.com/ernie/squeel - person stephan.com; 27.07.2011
comment
Хм... Просто мое мнение: я думаю, вы не слишком стараетесь. Я никогда не использовал групповое предложение в arel, однако я все чаще использую его с удовольствием. - person Pedro Rolo; 27.07.2011
comment
Для примера того, что работает в arel: users=User.arel_table; роли = Роль.arel_table; User.joins(:roles).where(roles[:name].eq(admin).and(user[id].gt(50))); комментарии= Комментарий.arel_table; Post.joins(:comments).order(comments[:id].count) - person Pedro Rolo; 27.07.2011

Arel был полностью переделан с нуля. Эта инициатива была начата тендерлавом (Аароном). Были проблемы с производительностью в основном составных запросах.

Я даже сам внес свой вклад в эту новую инициативу.

Arel теперь использует абстрактное синтаксическое дерево (в диспетчере выбора) и шаблон посетителя.

Вы также можете отказаться от того, как Arel 1.0.1 работает в версии 2.0.0 (на пути к 3.0.x для согласования с рельсами)

person Snuggs    schedule 04.11.2010