tags:

views:

16

answers:

2

Let's say I have three tables (with the columns in each):

USERS: id, name, account_id

ACCOUNTS: id, name

EVENTS: event_id, user_id, date

And I want to get the total count of events from EVENTS for each user, within a date range, along with the user's name and account name.

I can use GROUP BY to group the results by user_id, but how do I then join that to the users and accounts to get that info in each row? I'm trying to get an output like:

+-------+---------------------+--------+

| name  | account_name        |count(*)|

+-------+---------------------+--------+

| Joe   | XYZ, Inc.           |     10 |

| Bob   | Vandalay Industries |     21 |

| Mary  | Account Name Here   |     32 |

+-------+---------------------+--------+

where the third column is the total number of events in the EVENTS table for that user_id in a specified date range.

Sorry, I can never get the hang of joins like this..

+1  A: 

Assuming that you have an id column on users and accounts tables

SELECT 
 users.name,
 accounts.name,
 count(events.event_id)
FROM
 users
 INNER JOIN events ON events.user_id = users.id
 INNER JOIN accounts ON accounts.id = users.account_id
WHERE
 events.date between <startdate> AND <enddate>
GROUP BY
 users.name,
 accounts.name
Gaby
+1: Just like mine, but yours is without table aliases :)
OMG Ponies
This works perfectly. Thanks!
NChase
A: 

The obvious ways of doing it would be:

1) group the results of a join query:

SELECT users.name, accounts.name, COUNT(*)
FROM users, accounts, events
WHERE users.account_id=accounts.id
AND users.id=events.user_id
WHERE events.date>$START_DATE
AND events.date<$END_DATE
GROUP BY users.name, accounts.name;

2) ALternatively you could use the consolidated query on just events as a data source and join to that:

SELECT users.name, accounts.name, ilv.event_count
FROM (SELECT user_id, count(*)
  FROM events
  WHERE events.date>$START_DATE
  AND events.date<$END_DATE
  GROUP BY user_id) as ilv,
users, accounts
WHERE users.id=ilv.user_id
AND users.account_id=accounts.id;

HTH

C.

symcbean
There's a syntax error in the first query - duplicate "WHERE" keywords. See Gaby's answer for a better alternative.
OMG Ponies
@OMG Ponies: yes, the second 'where' should be an 'and'. Leaving that aside, Gaby's answer is the same as the first query I gave - however the DBMS could easily generate a very inefficient execution plan for this depending on the patterns in the data - hence my second query which is much less likely to perform badly.
symcbean
The second query is guaranteed to do two scans - one for the subquery and one for joining the other tables to it's result - effectively, it's not as efficient as Gaby's.
OMG Ponies
@OMG Ponies: You are talking nonsense. Yes, there will be access on each of the 3 tables - but that's true of **BOTH** methods. Whether or not those will be full table scans is impossible to tell from the information supplied, but the second method I've given will always be at most as expensive as the first.
symcbean
Claiming it's "impossible" doesn't validate your suggestion in any way - review the explain plan.
OMG Ponies