2016-09-30 81 views
5

celu wykazania mój problem, ja stworzyli fikcyjną bazę danych z tych 4 stołach (zdefiniowanego jako modele wymowny): Użytkownika, produkt, ShoppingItem (krótka: Przedmiot) Zamówienie; ze wszystkimi ich stosownymi relacjami. (użytkownika zawarte tu tylko dla kompletności)
produkty:Wymowne: jak dołączyć do bezpośrednio powiązanej tabeli i pośrednio powiązanego ze sobą tabeli?

  • id
  • Nazwa
  • hasMany (pozycja)

Zamówienia:

  • id
  • user_id
  • data
  • hasMany (poz)

przedmioty:

  • id
  • PRODUCT_ID
  • ORDER_ID
  • belongsTo (PRODUCT)
  • belongsTo (kolejności)

Tak (Zakupy) przedmioty zapisy są tworzone, gdy klient kupuje kilka produktów. Utworzono również zamówienie Zamówienie (wózek zakupowy) i zawiera 1 lub więcej elementów należących do dokładnie jednego klienta (Użytkownik) oraz jego bieżący proces zakupowy.

Teraz ten problem dotyczy listy produktów i sposobu analizy ich "sukcesu". Jak często są sprzedawane i , kiedy ostatni raz został sprzedany?

mogę na przykład użyć następującej kwerendy, aby uzyskać wszystkie Zamówienia dla pojedynczego produktu, a zatem liczyć, jak często są one sprzedawane:

$orders = Order::whereHas('items', function ($query) use ($id) { 
    $query->where('product_id', $id) 
      ->where('date', '<', Carbon::now()); 
})->orderBy('date', 'desc')->get(); 

Również mogę uzyskać listę wszystkie produkty zamówione przez czas zostały sprzedane z tym:

$products = Products::withCount('items') 
        ->orderBy('item_count', 'desc'); 

Ale chcę uzyskać listę wszystkich produktów, posortowane według daty, kiedy zostali ostatni nakazał (kupna- wynajęty). Ten wynik musi być kwerendą kwantową lub zestawem konstruktora kwerend, aby można było używać na nim podziału na strony.

Mam mutator zdefiniowane w moim modelu produktu, na przykład:

public function getLastTimeSoldAttribute($value) { 

    $id = $this->id; 

    // get list of plans using this song 
    $order = Order::whereHas('items', function ($query) use ($id) { 
     $query->where('product_id', $id) 
       ->where('date', '<', Carbon::now()); 
    })->orderBy('date', 'desc')->first(); 

    return $order->date; 
} 

Zwraca datę ostatniego zakupu tego produktu i można go używać w widoku jak ten:

{{ $product->last_time_sold }} 

Jednak nie mogę użyć "last_time_sold" w elokwentnym poleceniu OrderBy!

Czy istnieje inny sposób uzyskania wartości "last_time_sold" produktu w relacjach z bazą danych, jak opisano powyżej, bez utraty możliwości tworzenia stronicowania?

Docelowo, jaki jest właściwy sposób sprawdzania tabeli produktów i zamawiania produktów po raz ostatni, kiedy zostały zamówione?

Pamiętaj, że przedmioty nie mają daty, tylko zamówienie (Kartka na zakupy) ma datę.

+0

jeśli przedmioty donot mają datę, jak to jest '$ query -> where ('date', '<', Carbon :: now());' powinno działać? –

+0

Dobre pytanie! Ale z jakiegoś powodu działa ... a "data" jest w rzeczywistości polem Zleceń tabelowych, gdzie "id_produktu" to pole Elementów tabel. Więc w tym pod-zapytaniu najwyraźniej pozwala mi mieszać nazwy pól z obu tabel - o ile mają różne nazwy, tak myślę. Nie jestem ekspertem od Eloquent ... – matthiku

+0

Mogę uzyskać listę wszystkich * przedmiotów zakupowych * z danymi produktu i faktyczną datą zakupu kart (zamówienia), zamówioną przed tą datą: '$ items = Item :: with ('product', 'order') -> orderBy ('product_id', 'date') ', ale tworzy listę wszystkich produktów, nie wszystkich produktów (które są znacznie mniejsze). – matthiku

Odpowiedz

1

Użyj LEWEGO POŁĄCZENIA z tabelami items i orders, pogrupuj według products i zamów przez MAX(orders.date).

$products = Product::leftJoin('items', 'items.product_id', '=', 'products.id') 
    ->leftJoin('orders', 'orders.id', '=', 'items.order_id') 
    ->groupBy('products.id') 
    ->selectRaw('products.*, max(orders.date) as last_ordered') 
    ->orderBy('last_ordered', 'desc') 
    ->get(); 

ten będzie wykonywał następujące zapytanie:

select products.*, max(orders.date) as last_ordered 
from `products` 
left join `items` on `items`.`product_id` = `products`.`id` 
left join `orders` on `orders`.`id` = `items`.`order_id` 
group by `products`.`id` 
order by `last_ordered` desc 

UWAGA 1: Jeśli tylko chcesz dostać produkty, które zostały już zamówione - użyj join() zamiast leftJoin.

Uwaga 2: Jeśli uruchomić MySQL w trybie ścisłym (domyślny dla laravel 5.3) trzeba będzie obejmować wszystkie kolumny z products tabeli w klauzuli groupBy().

Uwaga 3: W przypadku produktów, które nigdy nie zostały zamówione, kolumna last_ordered będzie miała wartość NULL. W MySQL NULL jest zamawiany jako pierwszy przy użyciu ASC i ostatnio przy użyciu DESC. Ale AFAIK to nie jest udokumentowane. Więc jeśli nie chcesz polegać na tym zachowaniu, należy:

->orderbyRaw('max(orders.date) is null') 
->orderBy('last_ordered', 'desc') 
0

W zależności od tego, jak często będziesz wykonywania tej kwerendy, może lepiej byłoby stworzyć „last_ordered” kolumnę timestamp o produktach i dotknij go za każdym razem, gdy pojawi się zamówienie.

+0

Masz absolutną rację, ale w rzeczywistości nie jest to bardzo częste zapytanie. – matthiku