4

I have a table which stores which teacher (teacherid) works for which group (groupid) of pupils starting from the date startdate:

CREATE TABLE `pupilgroupteacher` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `groupid` smallint(5) unsigned NOT NULL,
 `startdate` date NOT NULL,
 `teacherid` int(10) unsigned DEFAULT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `date` (`groupid`,`startdate`),
 KEY `teacher` (`teacherid`),
 KEY `group` (`groupid`),
 CONSTRAINT `fk_pupilgroupteacher_2` FOREIGN KEY (`groupid`) REFERENCES `pupilgroup` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
 CONSTRAINT `fk_pupilgroupteacher_1` FOREIGN KEY (`teacherid`) REFERENCES `employee` (`personid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin

Having a teacher ID and a month, I need to find all groups for which this teacher worked (or is going to work) at least one day in the given month.

Note: For a given teacherid there may be more than one startdate (if, for example, a teacher worked for a group, was replaced with another teacher and then replaced back on a later startdate).

Andriy M
23.3k6 gold badges60 silver badges104 bronze badges
asked Jul 14, 2013 at 15:07

2 Answers 2

3

Another way to get the result is this. It finds first all groups that the teacher has surely taught (or is going to) by checking that she has started within the month and then in another subquery it finds - for every group - the last teacher that started at the first day of the month or earlier.

With the unique index you have on the table, the second subquery should be quite efficient. The first subquery would benefit from an index on (teacherid, startdate, groupid):

SELECT groupid
FROM pupilgroupteacher
WHERE teacherid = @teacher 
 AND startdate >= @month + INTERVAL 1 DAY
 AND startdate < @month + INTERVAL 1 MONTH
UNION DISTINCT
SELECT gg.groupid
FROM 
 ( SELECT DISTINCT groupid
 FROM pupilgroupteacher
 ) AS gd
 JOIN pupilgroupteacher AS gg
 ON gg.groupid = gd.groupid
 AND gg.startdate =
 ( SELECT MAX(gi.startdate)
 FROM pupilgroupteacher AS gi 
 WHERE gi.groupid = gd.groupid
 AND gi.startdate < @month + INTERVAL 1 DAY
 )
WHERE gg.teacherid = @teacher ;
answered Jul 14, 2013 at 20:03
3

It seems that the following code solves my problem:

SELECT DISTINCT groupid
FROM pupilgroupteacher x
WHERE teacherid=@teacher AND startdate<@month+INTERVAL 1 MONTH AND
NOT EXISTS(
SELECT *
FROM pupilgroupteacher
WHERE groupid=x.groupid AND teacherid!=@teacher AND startdate>x.startdate AND startdate<@month
)

(Here @month is the date of the first day of the specified month and @teacher is the teacher ID.)

But:

  • is this code error-free? Please help to check it.
  • can it be optimized to use fewer server resources?
answered Jul 14, 2013 at 15:29
3
  • 1
    I think it's correct but you (may) need to replace the AND startdate<@month) with AND startdate <= @month) (if as I assume, when a teacher starts to work at 1st of July, then the previous teacher counts as having taught in June only.) Commented Jul 14, 2013 at 19:43
  • @ypercube: You are right Commented Jul 15, 2013 at 11:03
  • Added missing groupid=x.groupid AND Commented Jul 17, 2013 at 15:54

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.