views:

38

answers:

2

I have the following tables:

CREATE TABLE `attendance_event_attendance` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`talk_id` varchar(200) NOT NULL,
`membersAttended_id` varchar(200) NOT NULL,
PRIMARY KEY (`id`),
KEY `attendance_event_attendance_9ace4e5a` (`talk_id`),
KEY `attendance_event_attendance_3c0dadb7` (`membersAttended_id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;

CREATE TABLE `attendance_member` (
`name` varchar(200) NOT NULL,
`telephone_number` varchar(200) NOT NULL,
`email_address` varchar(200) NOT NULL,
`membership_type` varchar(1) NOT NULL,
`membership_number` varchar(200) NOT NULL,
PRIMARY KEY (`membership_number`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

CREATE TABLE `attendance_talk` (
`title` varchar(200) NOT NULL,
`speaker` varchar(200) NOT NULL,
`date_of_talk` date NOT NULL,
PRIMARY KEY (`title`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

I want to select all the members that have not attended the two latest talks. The query i have written looks like this:

SELECT m.name 
  from attendance_member as m 
left outer join attendance_event_attendance as ea on (ea.membersAttended_id=m.membership_number) 
join attendance_talk as t on (ea.talk_id = t.title) 
where t.date_of_talk >= 2010-06-01 
  AND ea.membersAttended_id = null;

Is this correct? Or have i not understood joins correctly?
Thanks in Advance,
Dean

+1  A: 

A somewhat horrible approach, I fear - but one that should work...

SELECT m.name 
from attendance_member as m 
left outer join (
 SELECT ea.membersAttended_id
 FROM attendance_event_attendance as ea
 join attendance_talk as t on (ea.talk_id = t.title) 
 where t.date_of_talk >= 2010-06-01
 GROUP BY ea.membersAttended_id
 HAVING COUNT(*) = 2
) attendingmembers
ON attendingmembers.membersAttended_id = m.membership_number
WHERE attendingmembers.membersAttended_id IS NULL
Will A
Thank you. I guess i really need to work on my SQL... as im doing more database work.
Dean
@Dean - the above is quite sick - the date + HAVING COUNT(*) = 2 is awful, there are better ways, introducing another subquery to get 'the latest two talks' would be much better than having date_of_talk > some date.
Will A
+1  A: 

Pretty much exactly like you would say it in English

   Select Distinct m.name         -- Select names
   From attendance_member M       -- of members
      Where Not Exists            -- who did not attend the last two talks
        (Select * From attendance_event_attendance a   
           Join attendance_talk t
              On a.talk_id = t.title
         Where a.membersAttended_id = m.membership_number
            And (Select Count(*) From attendance_talk
                 Where date_of_talk >= t. date_of_talk) <= 2)

NOTE: The subquery:

 (Select * From attendance_event_attendance a   
     Join attendance_talk t
        On a.talk_id = t.title
  Where a.membersAttended_id = m.membership_number -- (correlated w/outer query)
     And (Select Count(*) From attendance_talk
          Where date_of_talk >= t. date_of_talk) <= 2)

returns the list of members who attended the talks which have 2 or fewer subsequent talks

Charles Bretana