Sometimes more than a simple column is needed. For example, we want to group our orders by the month they were created. To do this, we will use a raw expression:
Controller
$orders = Order::selectRaw( 'month(orders.order_time) as month, sum(order_p.quantity) as total_quantity, sum(orders.total) as order_total, count(distinct id) as total_orders') ->join( DB::raw('(select order_id, sum(quantity) as quantity from `order_product` group by order_id) as order_p'), 'order_p.order_id', '=', 'orders.id', ) // We are using the month() mysql function to get the month from the order_time column ->groupByRaw('month(orders.order_time)') ->orderBy('month') ->orderBy('total_orders', 'desc') ->get(); return view('examples.groupByRawMonthWithEloquent', [ 'orders' => $orders]);
This produces the following SQL query:
select month(orders.order_time) as month, sum(order_p.quantity) as total_quantity, sum(orders.total) as order_total, count(distinct id) as total_ordersfrom `orders` inner join (select order_id, sum(quantity) as quantity from `order_product` group by order_id) as order_p on `order_p`.`order_id` = `orders`.`id`group by month(orders.order_time)order by `month` asc, `total_orders` desc
Then in our view, we can display the columns needed, and they will be grouped by the month:
View
{{-- ... --}}<table class="table-auto w-full"> <thead> <tr> <th class="px-4 py-2">Date</th> <th class="px-4 py-2">Total</th> <th class="px-4 py-2">Total Items</th> <th class="px-4 py-2">Total Orders</th> </tr> </thead> <tbody> @foreach ($orders as $order) <tr> <td class="border px-4 py-2">{{ $order->month }}</td> <td class="border px-4 py-2">${{ number_format($order->order_total, 2) }}</td> <td class="border px-4 py-2">{{ $order->total_quantity }}</td> <td class="border px-4 py-2">{{ $order->total_orders }}</td> </tr> @endforeach </tbody></table>{{-- ... --}}
This can be used for any raw expression, not just the month. For example, we can group by the day:
Controller
$orders = Order::selectRaw( 'day(orders.order_time) as day, sum(order_p.quantity) as total_quantity, sum(orders.total) as order_total, count(distinct id) as total_orders') ->join( DB::raw('(select order_id, sum(quantity) as quantity from `order_product` group by order_id) as order_p'), 'order_p.order_id', '=', 'orders.id', ) ->groupByRaw('day(orders.order_time)') ->orderBy('day') ->orderBy('total_orders', 'desc') ->get(); return view('examples.groupByRawDayWithEloquent', [ 'orders' => $orders]);
This produces the following SQL query:
select day(orders.order_time) as day, sum(order_p.quantity) as total_quantity, sum(orders.total) as order_total, count(distinct id) as total_ordersfrom `orders` inner join (select order_id, sum(quantity) as quantity from `order_product` group by order_id) as order_p on `order_p`.`order_id` = `orders`.`id`group by day(orders.order_time)order by `day` asc, `total_orders` desc
You can find the Automated test example for this lesson in our repository or Month Test here and Day Test here.
The results of these queries will return false data because you are not grouping by the column that is the key to join the other table (order id). Obviously, a second request cannot be dispensed with, but then the algorithm is too complex. So all this makes no sense, it is better to make one request by grouping by orders.id, and by means of PHP to group by month.
Sorry, can you expand on this a bit more? It seems that you see a mistake here, but I'm not sure where (this was tested to make sure it works correctly). Would love to see if there's a mistake and improve it!
Execute the query without joining the table and compare the results (order_total, total_orders).
First of all, thank you for noticing this. It does have an issue if there are more products assigned to the order_products table, and our testing had some flaws in the logic. I will update this article soon with updated solution and possibly test-cases for everyone to ues.
Sorry about this
Hi, both examples were updated and tests were added for them!
Thank you for noticing this issue.