3

I have for tables : USER, SUBSCRIPTION, FAVORITE and HISTORY. I would like to count the number of subscription, the number of favorite and the number of history for each user

SELECT 
    U.idUser,
    COUNT(S.idUser) AS nb_sub,
    COUNT(F.idUser) AS nb_fav,
    COUNT(H.idUser) AS nb_his
FROM
    USER U,
    SUBSCRIPTION S, 
    HISTORY H, 
    FAVORITE F
WHERE
    U.idUser = S.idUser AND
    U.idUser = F.idUser AND
    U.idUser = H.idUser
GROUP BY
    U.idUser;

I've tried this but it is not the result I want..

Thanks for helping me

5
  • Just so we clear. You want to simply count number of rows in each table(looks like it to me from your question) or there is a more special requirement(give me number of users who favors subscription x, for example)? Commented Oct 26, 2016 at 8:28
  • Use three seperate select idUser, count(*)....from SUBSCRIPTION/HISTORY/FAVORITE in Derived Tables or CTEs and join them. Commented Oct 26, 2016 at 8:28
  • 1
    It would be helpful if you could describe your desired view on the data Commented Oct 26, 2016 at 8:30
  • 3
    Unrelated, but: you should really stop using those ancient, outdated and fragile implicit joins in the WHERE clause and start using an explicit JOIN operator Commented Oct 26, 2016 at 8:33
  • USER is a saved word how exactly are you referencing a table with that name without using qualifiers ("USER")? Commented Oct 26, 2016 at 10:10

3 Answers 3

4

Try this:

SELECT 
    U.idUser,
    (SELECT COUNT(*) FROM SUBSCRIPTION S WHERE U.idUser = S.idUser) AS nb_sub,
    (SELECT COUNT(*) FROM HISTORY H WHERE U.idUser = H.idUser) AS nb_fav,
    (SELECT COUNT(*) FROM FAVORITE F WHERE U.idUser = F.idUser) AS nb_his
FROM USER U
Sign up to request clarification or add additional context in comments.

Comments

2
select U.IDUser, 
       nb_sub,
       nb_fav,
       nb_his
from USER U
left join 
    (
    select idUser, count(*) as nb_sub from Subscription group by idUser
    ) S
  on U.idUser = S.idUser
left join 
    (
    select idUser, count(*) as nb_his from History group by idUser
    ) H
  on U.idUser = H.idUser
left join 
    (
    select idUser, count(*) as nb_fav from Favourite group by idUser
    ) F
  on U.idUser = F.idUser

4 Comments

Thanks a lot, this is exactly what I want !
I think that's a very ugly approach using sub-selects in the LEFT JOIN, because you can easily approach this by using the sub-selects in the SELECT part.
@LucasPierrat Did you check my solution?
@LucasPierrat What do you mean?
1

P.s.

Except for great performance, when facing the lack of table such as "USER", this approach present a major advantage since there is no need to use FULL JOIN nor to generate a sub-query that will function as the base for LEFT JOIN


Solution 1

select      *  

from        (           select 'U' as tab ,idUser from "USER"
            union all   select 'S'        ,idUser from Subscription
            union all   select 'F'        ,idUser from Favourite
            union all   select 'H'        ,idUser from History
            )
            pivot (count(*) for tab in ('S' as nb_sub,'F' as nb_fav,'H' as nb_hist))            
;

Solution 2

This solution has less clean syntax but gives you a lot of freedom to manipulate the data ,e.g. add the nb_total column

select      idUser

           ,count (decode (tab,'U',1))  as nb_user  -- If the data is good there supposed to be 1 record per user
           ,count (decode (tab,'S',1))  as nb_sub
           ,count (decode (tab,'H',1))  as nb_fav
           ,count (decode (tab,'F',1))  as nb_hist    

           ,count (*)                   as nb_total        

from        (           select 'U' as tab ,idUser from "USER"
            union all   select 'S'        ,idUser from Subscription
            union all   select 'F'        ,idUser from Favourite
            union all   select 'H'        ,idUser from History
            )

group by    idUser
;

3 Comments

This answer gets my vote. OP should test the different answers, it is very likely this will be a significant improvement in performance over the join based solutions.
@mathguy But he just mark the first answer as accepted, which is probably the worst. I must admit, that this answer also is a good alternative instead of using sub-queries in the select part
@rbr94 - actually your CORRELATED subqueries are even worse than a join, since they will require going over each table many times (in a join each table is read only once). Happily, the Optimizer will likely re-write your solution with correlated subqueries as a multiple join query, resulting in the same plan as John HC's solution. Dudu's solution is entirely different and will (probably) result in a much better plan.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.