Question

ok, so there are 3 elements from the database which i am using for this query.

Person, with person_id as primary key,

Learners_to_classes, with has its own primary key and two foreign keys, class_id and person_id

and classes which has a primary key class_id.

Learners_to_classes has many to many relationships with person and classes, how ever the two foreign keys together must be unique (a person cant attend the same class twice.

each class has its own course_id (to define what type of class it is).

There is over 40 thousand records in learners_to_classes, over 36 thousand records in person, and around 1,300 records in classes.

What I am trying to do, is count the people who have done one type of course, but not the others.

SELECT count(distinct ltc.person_id) AS participants,
       classes.classcode as classcode,
       DATE_FORMAT(classes.course_start_date, '%Y') AS YEARPeriod
FROM learners_to_classes AS ltc
INNER JOIN classes ON ltc.class_id = classes.class_id
WHERE classes.deleted=0
AND classes.course_id=1 
AND NOT EXISTS (SELECT *
                FROM learners_to_classes AS o
                INNER JOIN classes AS c ON o.class_id=c.class_id
                WHERE (c.course_id=2 OR c.course_id=4)
                AND o.person_id=ltc.person_id)
GROUP BY YEAR(classes.course_start_date), classcode

This query takes one hell of a long time too run, and i am hoping there might be a more efficient way to get the information.

Was it helpful?

Solution

Presumably, you want people who have taken course 1 but not course 4. You can do this with an aggregation query and a having clause. The following query returns the learners who have taken one class but not the other:

SELECT ltc.person_id
FROM learners_to_classes AS ltc INNER JOIN
     classes c
     ON ltc.class_id = c.class_id
WHERE c.deleted = 0
GROUP BY ltc.person_id
HAVING sum(c.course_id = 1) = 1 and
       sum(c.course_id = 4) = 0;

If you want just the number of such people, use this as a subquery:

SELECT COUNT(*)
FROM (SELECT ltc.person_id
      FROM learners_to_classes AS ltc INNER JOIN
           classes c
           ON ltc.class_id = c.class_id
      WHERE c.deleted = 0
      GROUP BY ltc.person_id
      HAVING sum(c.course_id = 1) = 1 and
             sum(c.course_id = 4) = 0
     ) l;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top