Shaunak Ohri
Shaunak Ohri

Reputation: 31

how to solve the issue with group by and aggregate function in postgresql

I am trying to write a query for dividing the two SQL statements but it shows me

 ERROR: column "temp.missed" must appear in the GROUP BY clause or be used in 
 an aggregate function
  SQL state: 42803

although when I do group by temp.missed, it seems to be working but shows wrong results because of multiple group by.

I have following tables in PostgreSQL

 create table test.appointments (
      appointment_id serial
      , patient_id integer references test.patients(id)
      , doctor_id integer references test.doctors(id)
      , appointment_time timestamp
      , appointment_status enum('scheduled','completed','missed')
      );

 create table test.visits (
      visit_id serial
      , patient_id integer references test.patients(id)
      , doctor_id integer references test.doctors(id)
      , walk_in_visit boolean
      , arrival_time timestamp
      , seen_time timestamp
      );

I have written following query for finding Missed appointment rate (missed appointments / total appointments) but its shows the above mentioned error.

  select tem.doctor_id, (temp.missed::float/tem.total) as ratio from 
    (select doctor_id, count(appointment_status) as missed from appointments 
     where appointment_status='missed' group by doctor_id)as temp
      join (select doctor_id, count(appointment_status) as total from 
      appointments group by doctor_id) as tem  on temp.doctor_id = 
       tem.doctor_id group by tem.doctor_id;

Upvotes: 3

Views: 1512

Answers (2)

Sami Kuhmonen
Sami Kuhmonen

Reputation: 31193

You can simplify the query a lot and if you are using PostgreSQL 9.4 you can use a very nice and clear syntax:

SELECT   doctor_id, 
     COUNT(appointment_status)::float
       FILTER (WHERE appointment_status='missed') / 
     COUNT(*) AS ratio
FROM     appointments
GROUP BY doctor_id

The FILTER will affect only the COUNT it is after, so in this case it will only count missed appointments.

Upvotes: 1

Mureinik
Mureinik

Reputation: 311978

You don't need all those subqueries - a count function applied to a case expression would be much simpler:

SELECT   doctor_id, 
         COUNT(CASE appointment_status 
                    WHEN 'missed' THEN 1 
                    ELSE NULL 
               END)::float / 
         COUNT(*) AS ratio
FROM     appointments
GROUP BY doctor_id

Upvotes: 1

Related Questions