Question

I have a VoteQuestion table: VoteQuestion(idUser → User, idQuestion → Content, isUp)

and a Question table: Question(idQuestion → Content, title)

I want to select the 5 questions with the best score (upvotes-downvotes).
An upvote is a VoteQuestion with isUp = TRUE and a downvote a VoteQuestion with isUp = FALSE.

I tried the following query, but it's not what I was looking for. It's giving the same score for every question.

WITH upvotes AS
( 
  SELECT COUNT(*) AS "a"
  FROM "VoteQuestion", "Question"
  WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
  AND "VoteQuestion"."isUp" IS TRUE
), 
downvotes AS
( 
  SELECT COUNT(*) AS "b"
  FROM "VoteQuestion", "Question"
  WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
  AND "VoteQuestion"."isUp" IS FALSE
)
SELECT "title", "Question"."idQuestion", upvotes."a"-downvotes."b" AS total
FROM "VoteQuestion", "Question", upvotes, downvotes
WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
GROUP BY "title", "Question"."idQuestion", upvotes."a", downvotes."b"
ORDER BY "total" DESC
LIMIT 5

Also tried this:

SELECT "title", "Question"."idQuestion", 
( SELECT COUNT(*) 
  FROM "VoteQuestion", "Question"
  WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
  AND "VoteQuestion"."isUp" IS TRUE
) AS upvotes, 
( SELECT COUNT(*) 
  FROM "VoteQuestion", "Question"
  WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
  AND "VoteQuestion"."isUp" IS FALSE
) AS downvotes, upvotes-downvotes AS total
FROM "VoteQuestion", "Question"
WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
GROUP BY "title", "Question"."idQuestion"
ORDER BY total DESC
LIMIT 5

but it says ERROR: column "upvotes" does not exist

How can I get the difference of the upvotes and downvotes in a column from the query?

Was it helpful?

Solution

With a conditional statement inline to convert your True and False values to numbers (1 and -1 respectively) you can simply sum up the votes like this:

SELECT
    q."title",
    q."idQuestion",
    sum(
       case
           when v."isUp" then 1
           else -1
       end
    ) AS total

FROM
    VoteQuestion v join Question q on v."idQuestion" = q."idQuestion"

GROUP BY
    q."title",
    q."idQuestion"

ORDER BY
    3 DESC

LIMIT 5

I haven't tried it yet but I'm pretty sure this works.

EDIT: Here's the SQLFiddle which runs successfully: http://sqlfiddle.com/#!15/df4ca/3

OTHER TIPS

Try this:

SELECT "title", "Question"."idQuestion", 
( SELECT COUNT(*) as upvotes
  FROM "VoteQuestion", "Question"
  WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
  AND "VoteQuestion"."isUp" IS TRUE
) AS upvt, 
( SELECT COUNT(*) as downvotes
  FROM "VoteQuestion", "Question"
  WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
  AND "VoteQuestion"."isUp" IS FALSE
) AS downvt, upvt.upvotes-downvt.downvotes AS total
FROM "VoteQuestion", "Question"
WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
GROUP BY "title", "Question"."idQuestion"
ORDER BY total DESC
LIMIT 5

Hope it helps you

UPDATE

Let's try this one:

SELECT "title", "Question"."idQuestion", 
upvotes, downvotes, upvotes-downvotes AS total
FROM "VoteQuestion", "Question",
( SELECT "idQuestion", COUNT(*) as upvotes
  FROM "VoteQuestion", "Question"
  WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
  AND "VoteQuestion"."isUp" IS TRUE GROUP BY "idQuestion"
) AS upvt, 
( SELECT "idQuestion", COUNT(*) as downvotes
  FROM "VoteQuestion", "Question"
  WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
  AND "VoteQuestion"."isUp" IS FALSE GROUP BY "idQuestion"
) AS downvt
WHERE "VoteQuestion"."idQuestion" = "Question"."idQuestion"
AND "VoteQuestion"."idQuestion" = downvt."idQuestion"
AND "VoteQuestion"."idQuestion" = upvt."idQuestion"
GROUP BY "title", "Question"."idQuestion"
ORDER BY total DESC
LIMIT 5
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top