Skip to main content

Given a clinic of physicians, patients and appointments, how to find an available appointment time for a given physician?

This is a variant of the [Not] Exists query pattern. Though we can write it with subqueries, performance will be crisper with a join. But finding data that is not there requires a join to data which is there. So in addition to tables for appointments, doctors and patients, we need a table of all possible appointment datetimes. Here's a schema illustrating the idea ...

-- ---------------------------------------------------------------------------
-- Appointments available

-- from the Artful Common Queries page
-- http://www.artfulsoftware.com/infotree/qrytip.php?id=98
-- ---------------------------------------------------------------------------

-- Given a clinic of physicians, patients and appointments, how to find an
-- available appointment time for a given physician?

-- This is a variant of the [Not] Exists query pattern. Though we can write it
-- with subqueries, performance will be crisper with a join. But finding data
-- that is not there requires a join to data which is there. So in addition
-- to tables for appointments, doctors and patients, we need a table of all
-- possible appointment datetimes.

-- Here's a schema illustrating the idea ...

CREATE TABLE a_dt (         -- POSSIBLE APPOINTMENT DATES AND TIMES
  d DATE,
  t TIME
);
CREATE TABLE a_drs (        -- DOCTORS
  did INT                   -- doctor id
);
CREATE TABLE a_pts (        -- PATIENTS
  pid INT
);
CREATE TABLE a_appts (      -- APPOINTMENTS
  aid INT,                  -- appt id
  did INT,                  -- doctor id
  pid INT,                  -- patient id
  d DATE,
  t TIME
);

-- Now we can apply the [Not] Exists query pattern. To find free appointment
-- datetimes for a given doctor in a given datetime range, we left join
-- possible appointments to existing appointments on date and time and doctor,
-- add Where conditions for desired appointment datetimes, and finally add a
-- Where condition that the appointment slot be null, i.e. free...

SELECT d.did, a.d, a.t
FROM a_dt AS a
LEFT JOIN a_appts AS ap USING (d,t)
LEFT JOIN a_drs AS d
   ON a.d = ap.d
  AND a.t = ap.t
  AND ap.did = d.did
  AND ap.did = 1
WHERE a.d BETWEEN desired_start_date AND desired_end_date
  AND a.t BETWEEN desired_start_time AND desired_end_time
  AND ap.aid IS NULL;