tags:

views:

928

answers:

4

What's wrong with this query:

SELECT co.*, mod.COUNT(*) as moduleCount, vid.COUNT(*) as vidCount 
 FROM courses as co, modules as mod, videos as vid 
 WHERE mod.course_id=co.id AND vid.course_id=co.id ORDER BY co.id DESC

In other words, how can I do it so with every record returned from 'courses', there's an additional column called 'modCount' which shows the number of records in the modules table for that course_id, and another called 'vidCount' which does the same thing for the videos table.

Error:

Error Number: 1064

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') as moduleCount, vid.COUNT() as vidCount FROM courses as co, ' at line 1

+1  A: 
SELECT co.*,
       (
       SELECT  COUNT(*)
       FROM    modules mod
       WHERE   mod.course_id = co.id
       ) AS modCount,
       (
       SELECT  COUNT(*)
       FROM    videos vid
       WHERE   vid.course_id = co.id
       ) AS vidCount
FROM   courses co
ORDER BY
        co.id DESC
Quassnoi
+1  A: 
SELECT co.*, m.ModCnt as moduleCount, v.VidCnt as vidCount 
FROM courses co
INNER JOIN (
     select count(*) AS ModCnt, co.id AS CoID
     from modules 
     group by co) m
    ON m.CoID = co.id
INNER JOIN (
     select count(*) AS VidCnt, co.id AS CoID
     from videos
     group by co) v
    ON v.CoID = co.id 
INNER JOIN videos vid 
    ON vid.course_id = co.id 
ORDER BY co.id DESC
Dave Markle
I just noticed this, modcnt, lol. Are you allowed to use 'cnt' as a shorthand in work related code? :D
Click Upvote
+3  A: 

Using subselects you can do:

SELECT co.*, 
    (SELECT COUNT(*) FROM modules mod WHERE mod.course_id=co.id) AS moduleCount, 
    (SELECT COUNT(*) FROM videos vid WHERE vid.course_id=co.id) AS vidCount
FROM courses AS co
ORDER BY co.id DESC

But be carefull as this is an expensive query when courses has many rows.

EDIT: If your tables are quite large the following query should perform much better (in favor of being more complex to read and understand).

SELECT co.*, 
    COALESCE(mod.moduleCount,0) AS moduleCount,
    COALESCE(vid.vidCount,0) AS vidCount
FROM courses AS co
    LEFT JOIN (
            SELECT COUNT(*) AS moduleCount, course_id AS courseId 
            FROM modules
            GROUP BY course_id
        ) AS mod
        ON mod.courseId = co.id
    LEFT JOIN (
            SELECT COUNT(*) AS vidCount, course_id AS courseId 
            FROM videos
            GROUP BY course_id
        ) AS vid
        ON vid.courseId = co.id
ORDER BY co.id DESC
Stefan Gehrig
the expense is an important thing to keep in mind, especially with several subselects.
cori
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'mod WHERE mod.course_id=co.id) as moduleCount, (SELECT COUNT(*) ' at line 2
Click Upvote
There was a "WHERE" left that didn't belong in there. Pleas have another try. If this doesn't work, your MySQL server does not support scalar subselects. Which version do you use?
Stefan Gehrig
I think i'm using mysql 5. I did try it without the where but it still didn't work
Click Upvote
MySQL 5 should be OK. Are you running ANSI mode?
Stefan Gehrig
Not sure. But if the code needs so much work then i'll just go with the simpler solution with the PHP. but i've upvoted your answer regardless :)
Click Upvote
MySQL lacks HASH JOIN, that's why the second query will perform poorer. It would be faster in SQL Server and Oracle, though.
Quassnoi
A: 

Shoot this. I did the job with some non-mysql code:

function getAllWithStats($info='*',$order='',$id=0)
{
    $courses=$this->getAll($info,$order,$id);

    foreach ($courses as $k=>$v)
    {
        $courses[$k]['modCount']=$this->getModuleCount($v['id']);
        $courses[$k]['vidCount']=$this->getVideoCount($v['id']);
    }

    return $courses;
}
Click Upvote
This is essentially the same as the subselect-solution. You're doing two extra queries for every row in the courses table, which is not very problematic if the courses table is not very large.
Stefan Gehrig
Looking at the subselect solution and the PHP solution it could be interesting which would perform better. Even though the PHP solution will have some network overhead as data has to be transmitted on the wire, the subselect soltion will suffer from the lack of the MySQL query cache for its subselects - although the complete query would be cached in the query cache.
Stefan Gehrig