6

Rozważmy Mam 15 kategoriach i 6 podkategorii i mam elementów tabeli gdzie mam zestaw rekordów, gdzie mam się pobrać w następujący sposóbJak zamienić zapytania, aby wydajnie działały w szynach?

category 1 ---> level 1 ---> 3 items with maximum price 
category 1 ---> level 2 ---> 3 items with maximum price 
    ... 
    ... 
    ... 
category 15 ---> level 6 ---> 3 items with maximum price 

i

@categories.each do |value| 
    @sub-categories.each do |value1| 
     array = Item.find(:all, :conditions => ["customer_id IN (?) AND category_id = ? AND sub-category_id = ?", @customer, value.id, value1.id], :order => 'price DESC', :limit => 3) 
      array.each do |value2| 
        @max_price_item_of_each_customer << value2 
      end 
      end 
     end 

ale ten zajęłoby to dużo czasu, ponieważ iteruje. Więc jak mogę to zmienić w taki sposób, że czas może zostać skrócony? Każda pomoc jest doceniana.

+1

Czy możesz podać konkretny przykład tego, co może być kategoria, Poziom i pozycja? Trudno mi zrozumieć strukturę danych. – Matthew

Odpowiedz

2

To wszystko zależy od skali zapisów z którymi pracujesz, ale jeśli pracujesz z rozsądną zestawie, to powinno być szybsze i zmniejszy swoje zapytania do 1.

@customer_id = 1 
@categories = [1, 2, 3] 
@subs  = [4, 5, 6] 

@max_price_item_of_each_customer = [] 
items = Item.where(customer_id: @customer, category_id: @categories, subcategory_id: @subcategories) 
items.group_by{|item| item.category_id}.each_pair do |category_id, category_items| 
    category_items.group_by{|item| item.subcategory_id}.each_pair do |subcategory_id, subcategory_items| 
    @max_price_item_of_each_customer += subcategory_items.sort{|x, y| y.price <=> x.price }.first(3) 
    end 
end 
+0

Dziękuję i to zadziałało dla mnie z małą zmianą. Brakuje znaku równości po "@max_price_item_of_each_customer +", który próbowałem edytować, ale nie mogłem, ponieważ jest to jedyna zmiana. – logesh

4

Spróbuj:

@max_price_item_of_each_customer = [] 
@categories.each do |value| 
     @max_price_item_of_each_customer += Item.find(:all, :conditions => ["customer_id IN (?) AND category_id = ? AND sub-category_id in (?)", @customer, value.id, @sub-categories.map(&:id)], :order => 'price DESC', :limit => 3)    
end 
+0

Spróbuję tego. Ale przedtem możesz mi powiedzieć, w jaki sposób otrzymasz 3 przedmioty z każdej podkategorii. Myślę, że przyniosłoby to 3 przedmioty dla każdej kategorii. – logesh

+0

Próbowałem i wybiera 3 elementy dla każdej kategorii, a nie dla każdej podkategorii. – logesh

1

Poniższe rozwiązanie może działać, jeśli używasz PostgreSQL.

  1. Wybierz grupę 3 identyfikatory elementu z items tabeli klasyfikowane według price malejącej i pogrupowane według category_id i subcategory_id. Możesz użyć PostgreSQL array_agg, aby zebrać identyfikatory przedmiotów po grupowaniu.
  2. Wybrać wiersz pozycji, w którym identyfikatory pozycji znajdują się w tych identyfikatorach pozycji zgrupowanych. Po tym, zamówić wynik przez category_id rosnącym, subcategory_id wstępujących i price zstępującej

Rezultatem jest ActiveRecord::Relation, więc można iteracyjne pozycje jak zwykle. Ponieważ wynik jest spłaszczony (ale już uporządkowany według kategorii, podkategorii i ceny), musisz samodzielnie rozdzielić kategorie i podkategorie.

grouped_item_ids = Item.where(customer_id: customer_id). 
    select("items.category_id, items.subcategory_id, (array_agg(items.id order by items.price desc))[1:3] AS item_ids"). 
    group("items.category_id, items.subcategory_id").map {|item| item["item_ids"]} 
@items = Item.where(id: grouped_item_ids.flatten). 
    order("items.category_id ASC, items.subcategory_id ASC, items.price desc") 
1

następujące zapytanie działa na mnie

@max_price_item_of_each_customer =Item.find_by_sql(["SELECT i1.* FROM item i1 
     LEFT OUTER JOIN item i2 ON (i1.category_id = i2.category_id AND i1.sub-category_id = i2.sub-category_id AND i1.id < i2.id) 
     WHERE i1.customer_id IN (?) AND i1.category_id IN (?) 
     GROUP BY i1.id HAVING COUNT(*) < 3 
     ORDER BY price DESC", @customer, @categories.map(&:id)])