I have a query that currently works but based is inefficient. I'm basically trying to group both labor and sales data by the hour.
And I want to be able to do it by giving the query a day.
I'm using PostgreSQL.
I have a bunch of time punch records that have the employee_id
, job_id
and location_id
but if the employee has clocked in and hasn't clocked out I have to check the clock_out_time field and set it to now()
to properly do the hourly calculation.
Planning time: 0.509 ms
Execution time: 0.498 ms
I'm doing this with 30-50 records so this will not scale.
What can I do to improve this?
SELECT
date_trunc('hour', tp.clock_in_time) AS hour,
SUM(
(
EXTRACT (DAY FROM (CASE WHEN EXTRACT(YEAR FROM tp.clock_out_time) = -1 THEN now() ELSE tp.clock_out_time END - tp.clock_in_time))*24*60*60+
EXTRACT (HOUR FROM (CASE WHEN EXTRACT(YEAR FROM tp.clock_out_time) = -1 THEN now() ELSE tp.clock_out_time END - tp.clock_in_time))*60*60+
EXTRACT (MINUTE FROM (CASE WHEN EXTRACT(YEAR FROM tp.clock_out_time) = -1 THEN now() ELSE tp.clock_out_time END - tp.clock_in_time))*60+
EXTRACT (SECOND FROM (CASE WHEN EXTRACT(YEAR FROM tp.clock_out_time) = -1 THEN now() ELSE tp.clock_out_time END - tp.clock_in_time))
) / 60 / 60.00 * (job.rate / 100.00)
) AS labor_costs,
(
SELECT
SUM(total) / 100.00
FROM
ticket
WHERE
open=false
AND
DATE_TRUNC('day', opened_at) = date_trunc('day', '2018-12-22T11:15:05-05:00'::date)
AND
DATE_TRUNC('day', closed_at) = date_trunc('day', '2018-12-22T11:15:05-05:00'::date)
GROUP BY date_trunc('hour', opened_at)
ORDER BY date_trunc('hour', opened_at)
) AS hourly_sales
FROM
employee_time_punch as tp
INNER JOIN
employee
ON
employee.id = tp.employee_id
INNER JOIN
employee_job as job
ON
job.id = tp.job_id
WHERE
DATE_TRUNC('day', tp.clock_in_time) = DATE_TRUNC('day', '2006-01-02T11:15:05-05:00'::date)
AND
DATE_TRUNC('day', CASE WHEN EXTRACT(YEAR FROM tp.clock_out_time) = -1 THEN now() ELSE tp.clock_out_time END) = DATE_TRUNC('day', '2006-01-02T11:15:05-05:00'::date)
GROUP BY 1
ORDER BY 1;