Laravel eloquent agrupa registros eloquent en intervalos de una hora con Left join.
Estoy utilizando Laravel v8 y tengo dos tablas con la siguiente estructura:
orders
id | total | created_at |
---|---|---|
1 | 100 | 2022-01-01 11:00:05 |
2 | 300 | 2022-01-01 15:00:05 |
.. | .. | … |
order_items
id | order_id | product_id | quantity |
---|---|---|---|
1 | 1 | 2 | 1 |
2 | 1 | 4 | 3 |
.. | .. | .. | .. |
Deseo generar un informe que consista en un resumen de los pedidos en cada intervalo de una hora (59 minutos y 59 segundos) durante un día, por ejemplo, como esto:
Fecha | Hora | Total de pedidos | Cantidad total de productos en pedidos | Monto total de pedidos |
---|---|---|---|---|
01 de enero de 2020 | 00:00 – 00:59 | 0 | 0 | 0 |
01 de enero de 2020 | 01:00 – 01:59 | 0 | 0 | 0 |
01 de enero de 2020 | 02:00 – 02:59 | 0 | 0 | 0 |
01 de enero de 2020 | 03:00 – 03:59 | 1 | 2 | 80 |
01 de enero de 2020 | 04:00 – 04:59 | 3 | 10 | 500 |
01 de enero de 2020 | 05:00 – 05:59 | 0 | 0 | 0 |
………… | ………….. | … | … | … |
01 de enero de 2020 | 21:00 – 21:59 | 5 | 18 | 1020 |
01 de enero de 2020 | 22:00 – 22:59 | 1 | 5 | 210 |
01 de enero de 2020 | 23:00 – 23:59 | 0 | 0 | 0 |
Actualmente tengo que seleccionar cada intervalo de esta forma y luego hacer un bucle foreach para resumir los datos para cada intervalo:
$orders = DB::table('orders')
->select(
[
DB::RAW('orders.total as total'),
DB::RAW('order_items.quantity as quantity')
]
)
->leftJoin ('order_items AS order_items.', function ($query) {
$query->on('order_items.order_id', '=', 'orders.id');
})
->whereBetween('orders.created_at',[date('Y-m-d 00:00:00'),date('Y-m-d 00:59:59')])
->get();
$totalOrder = $orders->count();
$totalQuantity = 0;
$totalAmount = 0;
foreach($orders as $order){
$totalQuantity += $order->quantity;
$totalAmount += $order->total;
}
$data['00:00 - 00:59'] = [
'total_order' => $totalOrder,
'total_quantity' => $totalQuantity,
'total_amount' => $totalAmount,
];
Esta solución funciona, pero no es muy eficiente. ¿Cómo puedo ejecutar una sola consulta en la base de datos para lograr este tipo de resultado?
davy.ai
Para generar el informe con una sola consulta, puedes usar el ORM Eloquent de Laravel y las funciones GROUP BY y DATE_FORMAT en tu consulta. Aquí tienes un ejemplo de consulta que debería darte los datos del informe que necesitas:
En esta consulta, primero seleccionamos la fecha y el intervalo de tiempo basado en el campo
created_at
usando las funcionesDATE_FORMAT
yCONCAT
. También usamos las funcionesCOUNT
ySUM
para obtener el total de órdenes, la cantidad total de artículos de la orden y el monto total de la orden para cada intervalo de tiempo. Hacemos un left join con la tablaorder_items
para incluir la cantidad de artículos de la orden en el resumen.Luego usamos la función
whereDate
para filtrar las órdenes por la fecha para la cual quieres generar el informe, y agrupamos los resultados por fecha e intervalo de hora usando las funcionesGROUP BY
yFLOOR
. Finalmente, ordenamos los resultados por fecha e intervalo de tiempo usando la funciónorderBy
.Esta consulta devolverá una colección de objetos que contienen los datos del informe para cada intervalo de tiempo en la fecha dada. Puedes recorrer esta colección para mostrar el informe en el formato deseado.
Nota: La función
IFNULL
se utiliza para manejar los casos en los que una orden puede no tener ningún artículo. En tales casos, la cantidad de artículos de la orden será nula, por lo que utilizamos la funciónIFNULL
para reemplazarla por 0.