Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add together the results of several subqueries?

Tags:

sql

mysql

I am running a MySQL query to rank my site's users according to the number of book reviews and recipe reviews they have contributed. After initial issues with a multiple JOIN query, I've switched to a series of subqueries, which is much, much faster. However, although I can extract the numbers of reviews from each member, I can't figure out how to add them together so I can sort by the total number.

Here's the current query:

SELECT users.*,
   (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles,
   (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews,
   (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews
FROM users   

I need to add together bookreviews and recipereviews to get 'reviewtotals'. MySQL won't allow you to use simple syntax to do calculations on aliases, but I presume there's another way to do this??

like image 962
mandel Avatar asked Jan 11 '10 14:01

mandel


2 Answers

Wrap it into a subquery:

SELECT  *,
        bookreviews + recipereviews AS totalreviews
FROM    (
        SELECT  users.*,
                (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles,
                (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews,
                (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews
        FROM    users   
        ) q
like image 131
Quassnoi Avatar answered Sep 23 '22 12:09

Quassnoi


If you want to be safe and fast, do it like this:

SELECT users.*
,      titles.num                            titles
,      book_reviews.num                      book_reviews
,      recipe_reviews.num                    recipe_reviews
,      book_reviews.num + recipe_reviews.num total_reviews
FROM      users   
LEFT JOIN (
          SELECT   user_ID, count(*) AS num
          FROM     bookshelf
          GROUP BY user_ID
          ) as titles
ON        users.ID = titles.user_ID
LEFT JOIN (
          SELECT   user_ID, count(*) AS num
          FROM     book_reviews
          GROUP BY user_ID
          ) as book_reviews
ON        users.ID = reviews.user_ID
LEFT JOIN (
          SELECT   user_ID, count(*) AS num
          FROM     recipe_reviews
          GROUP BY user_ID
          ) as recipe_reviews
ON        users.ID = recipes.user_ID

If you want to stick to the subqueries in the SELECT list, and want it to be safe, take a look at Quassnoi's solution.

If you like to live a bit dangersouly and still want a fast result, you can use user-defined variables. I predict it will be safe in this very particular case:

SELECT users.*,
       (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles,
       @bookreviews:=(
           SELECT count(*) 
           FROM book_reviews 
           WHERE book_reviews.user_id = users.ID
       ) as bookreviews,
       @recipereviews:=(
           SELECT count(*) 
           FROM recipe_reviews 
           WHERE recipe_reviews.user_id = users.ID
       ) as recipereviews,
       @bookreviews + @recipereviews as total_reviews
FROM users   
like image 33
Roland Bouman Avatar answered Sep 22 '22 12:09

Roland Bouman