2013-09-24 2 views
4

Я унаследовал проект Rails3 другого программиста, и я довольно новичок в рельсах в целом. У него есть запрос, который сортируется по определенным идентификаторам. Может ли кто-нибудь объяснить, как это происходит в реальном SQL? Я думаю, что этот код убивает db и впоследствии рельсы. Я попытался вывести его в регистраторе, но, похоже, не может получить фактический SQL для вывода даже с настройкой конфигурации: debug. Поиск тяжело здесь (на SO) не выявил четкого объяснения того, как выглядит этот запрос. Код выглядит следующим образом:Сортировать по определенным идентификаторам в ActiveRecord

options = { 
       select: "SUM(1) AS num_demos, product_id ", 
       group: "product_id",     
       order: "num_demos ASC", 
      } 
    product_ids = Demo.where("state = 'waitlisted'").find(:all, options).collect{|d| d.product_id} 
    sort_product_ids = product_ids.collect{|product_id| "id = #{product_id}"} 
    Product.where(visible: true, id: product_ids).order(sort_product_ids.join(', ')) 

Насколько я понимаю, последняя строка будет создать запрос к таблице продукта с ORDER BY «ID = 1, ID = 3, ...» и т.д., которые не имеет большого смысла для меня. Все подсказки оценили.

+1

использования 'to_sql' в конце запроса и проверить его, чтобы увидеть SQL генерируется – tihom

+0

Спасибо, получил тот же результат с рельсов консоли. Это выглядит так: SELECT "products". * FROM "products" WHERE "products". "Visible" = 't' AND "products". "Id" IN (166, 105, .. и т. Д.) ORDER BY id = 166 , id = 105, id = 110, id = 99, id = 109, id = 118, id = 108, id = 160, ... и т. д. Я еще не видел этот тип ORDER BY, и это довольно круто , –

ответ

1

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

options = { 
       select: "SUM(1) AS num_demos, product_id ", 
       group: "product_id",     
       order: "num_demos ASC", 
      } 
product_ids = Demo.where("state = 'waitlisted'").find(:all, options).collect{|d| d.product_id} 

Эта линия будет генерировать

SELECT SUM(1) as num_demos, product_id FROM "demos" WHERE (state = 'waitlisted') GROUP BY product_id 

И возвращает массив Demo объектов, отсортированных по count(*) строк в группе, где был загружен только атрибут product_id и доступен для вас ,

Далее

sort_product_ids = product_ids.collect{|product_id| "id = #{product_id}"} 

результаты в коллекции product_ids, преобразованных в формат "id = x". IE: Если предыдущий результат, возвращаемый 10 результатов, с product_ids в пределах от 1..10, sort_product_ids теперь эквивалентно ["id = 1", "id = 2", "id = 3", "id = 4", "id = 5", "id = 6", "id = 7", "id = 8", "id = 9", "id = 10"]

Наконец,

Product.where(visible: true, id: product_ids).order(sort_product_ids.join(', ')) 

Выбирает все Products где столбец visible является true, и их id находится в массиве product_ids (который, как мы выяснили ранее, на самом деле представляет собой массив из Demo объектов, а не целых чисел - это может привести к сбою запроса). Затем он запрашивает SQL для сортировки этого списка результатов с помощью sort_product_ids (отправляется как строка "id = 1, id = 2, ... id = 10" вместо массива ["id = 1", "id = 2", ... "id = 10"]).

Дополнительная информация доступна по адресу: http://guides.rubyonrails.org/active_record_querying.html http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html

+0

спасибо за этот полезный анализ. В моих тестах в irb массив sort_product_ids имел бы записи типа «id = 1», «id = 2» и т. Д. Когда вы вызываете join (','), вы должны получить одну строку со всеми этими элементами: «id = 1, id = 2» и т. д. Так что ActiveRecord фактически создает SQL, который говорит ... ORDER BY ('id = 1, id = 2, ...')? –

+0

К сожалению, это означает, что - обновлено! – Momer

+0

Спасибо большое, @Morner. Хотелось бы проголосовать за этот ответ, но у меня недостаточно репутации ... –

1

Для выбора и сортировки по данному массиву идентификаторов вы можете использовать этот

Product.where(visible: true, id: product_ids) 
.order("field(id,#{product_ids.join(',')})") 
+0

Вы имеете в виду, что он будет выбирать только записи с указанными идентификаторами и возвращать их в порядке идентификаторов, как предусмотрено product_ids.join (',')? –

+0

он выберет записи с указанными идентификаторами и 'visible = true'. Затем он устроит их по заданному порядку. Если «продукт» не присутствует в конечном результате, он просто игнорирует свой «id» в заказе. – tihom

+0

Это именно то, что я искал.Он заказал мою модель определенным набором идентификаторов. – tolgap

Смежные вопросы