tags:

views:

24

answers:

1

MySQL - Why does count() change the behavior of join

I have a simple case. Events and attendees. In my test below there are no attendees yet I still want a list of events so I use an outer join and that works. However if I want a list of events and the count of attendees it only returns the first row. Why

CREATE TABLE IF NOT EXISTS `event` (
 `event_id` int(11) NOT NULL AUTO_INCREMENT,
 `event_name` varchar(50) NOT NULL,
 PRIMARY KEY (`event_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

CREATE TABLE IF NOT EXISTS `attendees` (
  `event_id` int(11) NOT NULL,
  `attendee` varchar(50) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `event` (`event_id`, `event_name`) 
VALUES
 (1, 'event one'),
 (2, 'event two'),
 (3, 'event three');

   SELECT e.*, a.attendee 
     FROM `event` e
left outer join attendees a on e.event_id = a.event_id

returns:

event_id   event_name   attendee
---------------------------------
1          event one    NULL
2          event two    NULL
3          event three  NULL

However:

SELECT e.*, count(a.attendee) 
  FROM `event` e
left outer join attendees a on e.event_id = a.event_id

only returns:

event_id     event_name    count(a.attendee)
---------------------------------------------
1            event one     0

Why?

+3  A: 

When you add an aggregate function without specifying a GROUP BY you get one row corresponding to a single group consisting of all rows.

If you want a count per group you should add an explicit GROUP BY clause.

SELECT e.*, COUNT(a.attendee)
FROM `event` e
LEFT OUTER JOIN attendees a ON e.event_id = a.event_id
GROUP BY e.event_id
Mark Byers
perfect - that works!SELECT e.*, count(a.attendee) FROM `event` eleft outer join attendees a on e.event_id = a.event_idgroup by event_id
sdfor
What would you change if I need both the count of attendees and the list of addendees?
sdfor
@sdfor: I'd make two separate queries. Or query for the list of attendees and then count them in the client.
Mark Byers
Thanks Mark, I think in my case your second choice makes sense. But it seems as you say, I can't combine getting both an aggregate and details in one SELECT.
sdfor