I am using MySQL and want to create a query that will count how many times appointments happened per contact_id within the last year, last year, and how many times the occurrence happened overall.
My appointment table has the following rows with sample data:
id | contact_id | appointment_date | status_id
1 | 1 | 2019-01-01 | Attended
2 | 1 | 2018-05-01 | Attended
3 | 2 | 2019-04-01 | Cancelled
4 | 2 | 2019-05-01 | No Show
5 | 1 | 2018-07-01 | Cancelled
6 | 1 | 2019-08-01 | Not Complete
So let’s say I want to see how many times contact_id ‘1’ had appointments, here how I’d want the result to look:
Status | Total overall | Total this year | Total last year
Attended | 2 | 1 | 1
Cancelled | 1 | 0 | 1
No Show | 0 | 0 | 0
Not Complete | 1 | 1 | 0
Is this query do-able with MYSQL?
I will be using it in an HTML/PHP/jQuery web application. I am going to have a button that will generate this information once clicked. Perhaps I should scrap the query idea and somehow manipulate it using some sort of jQuery table/data manipulation after a simple
‘SELECT * from appointments WHERE contact_id = 1'
?
Advertisement
Answer
If you’d like to have it in a single query, you can try something like this:
SELECT
status_id
, COUNT(*) AS `Total overall`
, SUM(IF(YEAR(appointment_date) = YEAR(CURDATE()), 1, 0)) AS `Total this year`
, SUM(IF(YEAR(appointment_date) = YEAR(CURDATE()) - 1, 1, 0)) AS `Total last year`
FROM
appointment
WHERE
contact_id = 1
GROUP BY
status_id
=>
status_id total total_this_year total_last_year
Attended 2 1 1
Cancelled 1 0 1
Not Complete 1 1 0
The above query will not return information for ‘No Show’. If you really need all statuses, you can do something like this:
SELECT
s.status_id
, IFNULL(a.total, 0) AS `Total overall`
, IFNULL(a.total_this_year, 0) AS `Total this year`
, IFNULL(a.total_last_year, 0) AS `Total last year`
FROM
(
SELECT
DISTINCT status_id
FROM
appointment
) AS s
LEFT JOIN (
SELECT
status_id
, COUNT(*) AS `total`
, SUM(IF(YEAR(appointment_date) = YEAR(CURDATE()), 1, 0)) AS `total_this_year`
, SUM(IF(YEAR(appointment_date) = YEAR(CURDATE()) - 1, 1, 0)) AS `total_last_year`
FROM
appointment
WHERE
contact_id = 1
GROUP BY
status_id
) AS `a` ON (
a.status_id = s.status_id
)
=>
status_id Total overall Total this year Total last year
Attended 2 1 1
Cancelled 1 0 1
Not Complete 1 1 0
No Show 0 0 0
P.S. I do not like the years calculations I used in the query, however, keeping it as is here for simplicity.
In real life, I’d use range comparison appointment_date BETWEEN CONCAT(YEAR(CURDATE()), '-01-01') AND CONCAT(YEAR(CURDATE()), '-12-31')
instead of YEAR(appointment_date) = YEAR(CURDATE())
.