tags:

views:

81

answers:

2

My tables:

suggestions:
suggestion_id|title|description|user_id|status|created_time

suggestion_comments:
scomment_id|text|user_id|suggestion_id

suggestion_votes:
user_id|suggestion_id|value

Where value is the number of points assigned to a vote.

I'd like to be able to SELECT: suggestion_id, title, the number of comments and the SUM of values for that suggestion. sorted by SUM of values. LIMIT 30

Any ideas?

+2  A: 

You may want to try using sub queries, as follows:

SELECT  s.suggestion_id,
        (   
           SELECT COUNT(*) 
           FROM suggestion_comments sc 
           WHERE sc.suggestion_id = s.suggestion_id
        ) num_of_comments,
        (   
           SELECT SUM(sv.value) 
           FROM suggestion_votes sv
           WHERE sv.suggestion_id = s.suggestion_id
        ) sum_of_values
FROM    suggestions s;

Test case:

CREATE TABLE suggestions (suggestion_id int);
CREATE TABLE suggestion_comments (scomment_id int, suggestion_id int);
CREATE TABLE suggestion_votes (user_id int, suggestion_id int, value int);

INSERT INTO suggestions VALUES (1);
INSERT INTO suggestions VALUES (2);
INSERT INTO suggestions VALUES (3);

INSERT INTO suggestion_comments VALUES (1, 1);
INSERT INTO suggestion_comments VALUES (2, 1);
INSERT INTO suggestion_comments VALUES (3, 2);
INSERT INTO suggestion_comments VALUES (4, 2);
INSERT INTO suggestion_comments VALUES (5, 2);
INSERT INTO suggestion_comments VALUES (6, 3);

INSERT INTO suggestion_votes VALUES (1, 1, 3);
INSERT INTO suggestion_votes VALUES (2, 1, 5);
INSERT INTO suggestion_votes VALUES (3, 1, 1);
INSERT INTO suggestion_votes VALUES (1, 2, 4);
INSERT INTO suggestion_votes VALUES (2, 2, 2);
INSERT INTO suggestion_votes VALUES (1, 3, 5);

Result:

+---------------+-----------------+---------------+
| suggestion_id | num_of_comments | sum_of_values |
+---------------+-----------------+---------------+
|             1 |               2 |             9 |
|             2 |               3 |             6 |
|             3 |               1 |             5 |
+---------------+-----------------+---------------+
3 rows in set (0.00 sec)

UPDATE: @Naktibalda's solution is an alternative solution that avoids sub queries.

Daniel Vassallo
Is there a way not to use sub queries? I just heard their slower.
Steven
Yes, you are right, 2 subqueries are executed for each suggestion so thats rather slow.
Naktibalda
@Steven, @Naktibalda: In general this won't be slow if the `suggestion_id` of each table is properly indexed, (and as long as the query won't return many suggestions)... In addition, it can get quite complicated to do multiple aggregations on a single result set.
Daniel Vassallo
After testing you seem corrent, and your solution is easier to read
Steven
+2  A: 

I was typing the same query as potatopeelings.
But there is an issue:
Resultset after joins contains M*N rows (M-number of comments, N-number of votes, not less than 1) for each suggestion.

To avoid that you have to count distinct comment ids and divide a sum of votes by number of comments.

SELECT 
    s.*, 
    COUNT(DISTINCT c.scommentid) AS comment_count,
    SUM(v.value)/GREATEST(COUNT(DISTINCT c.scommentid), 1) AS total_votes
FROM suggestions AS s
LEFT JOIN suggestion_comments AS c ON s.suggestion_id = c.suggestion_id 
LEFT JOIN suggestion_votes AS v ON s.suggestion_id = v.suggestion_id
GROUP BY s.suggestion_id
ORDER BY total_votes DESC
LIMIT 30
Naktibalda
#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 ' 1) AS total_votesFROM suggestions AS sLEFT JOIN suggestion_comments AS c ON' at line 4
Steven
Oh, I had to use GREATEST() instead of MAX()
Naktibalda