#sql #ruby-on-rails-3 #postgresql #group-by
#sql #ruby-on-rails-3 #postgresql #групповое по
Вопрос:
Необходимо создать запрос «Top 10», который работает с SQLite и Postgres.
Клиентская модель Клиент has_many :merchandises, :through => :orders, :source => :items
Я хочу сгруппировать товары, заказанные по product_id, получить количество для каждого и отсортировать по большинству продуктов, заказанных сверху, и ограничить до 10.
Client.last.merchandises.group(:product_id).count(:quantity)
SELECT COUNT("items"."quantity") AS count_quantity, product_id AS product_id FROM "items" INNER JOIN "orders" ON "items"."order_id" = "orders"."id" WHERE "orders"."client_id" = 2 GROUP BY product_id
=> {1=>91, 2=>1, 12=>1, 32=>1, 33=>1, 34=>1, 37=>1, 75=>1, 84=>1, 85=>1}
Чего не хватает: сортировка по, ограничение до 10 и получение product.name наряду с подсчетом количества
Последняя разработка:
Элементы выбраны, но должны отображаться product.name
class Client < ActiveRecord::Base
def top_ten_products
Item.find_by_sql(
"SELECT i.product_id, sum(i.quantity) AS sum_quantity
FROM orders o
JOIN items i ON i.order_id = o.id
WHERE o.client_id = 2
GROUP BY 1
ORDER BY 2 DESC
LIMIT 10;"
)
end
Вывод на консоль
=> [#<Item product_id: 1>, #<Item product_id: 37>, #<Item product_id: 75>, #<Item product_id: 12>, #<Item product_id: 32>, #<Item product_id: 33>, #<Item product_id: 2>, #<Item product_id: 34>, #<Item product_id: 84>, #<Item product_id: 85>]
Клиент #показать
<%= @client.top_ten_products %>
Ответ №1:
Предполагая, что product_id
это столбец таблицы items
, запрос может выглядеть следующим образом в PostgreSQL:
SELECT i.product_id
,p.name
,sum(i.quantity) AS sum_quantity
FROM orders o
JOIN items i ON i.order_id = o.id
LEFT JOIN product p USING (product_id)
WHERE o.client_id = 2
GROUP BY 1,2
ORDER BY 3 DESC, 2 -- with same quantity, order by name
LIMIT 10;
Примечание:
Я изменил вашу агрегацию количества на a sum
и добавил столбец с комментариями для count
, поскольку я подозреваю, что у вас ошибочно было количество, в котором вы хотите получить сумму.
Правка2:
sum()
подтверждено. Включено имя из таблицы product для каждого запроса.
LEFT JOIN
это просто мера предосторожности для отсутствующих записей в таблице product
, если ссылочная целостность гарантирована, вместо этого она может быть простой JOIN
.
Комментарии:
1. Спасибо. Почти есть. Я отредактировал свой вопрос выше с помощью последней разработки
2. Спасибо за обновление, однако в разделе item нет столбца name. Столбец name является частью таблицы product. Пожалуйста, сообщите.
3. @Gaelle: я отредактировал свое предположение. Если это не так, вам необходимо предоставить информацию о том, как таблица
product
связана с таблицейitem
.4. Вот где я не уверен. На данный момент у меня
Item belongs_to :product
ничего нет в таблице продуктов, поскольку я не уверен, как это должно быть установлено. Пожалуйста, сообщите. Спасибо5. @Gaelle: вы видите столбец
product_id
в обеих таблицах? Итак, работает ли моя последняя версия? Просто попробуйтеSELECT * FROM product LIMIT 10
иSELECT * FROM item LIMIT 10
посмотрите и выясните, как они связаны друг с другом.