Question

I have two entities: Proposal and Vote.

  • Proposal: A user can make a proposition.
  • Vote: A user can vote for a proposition.
CREATE TABLE `proposal` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
);

CREATE TABLE `vote` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `idea_id` int(11) NOT NULL,
  `updated` datetime NOT NULL,
  PRIMARY KEY (`id`),
);

Now I want to fetch rising Propsals, which means:

  • Proposal title
  • Total number of all time votes
  • has received votes within the last 3 days

I am trying to fetch without a subSELECT because I am using doctrine which doesn't allow subSELECTs. So my approach is to fetch by joining the votes table twice (first for fetching the total amount of votes, second to be able to create a WHERE clause to filter last 3 days) and do a INNER JOIN:

SELECT
  p.title,
  COUNT(v.p_id) AS votes,
  DATEDIFF(NOW(), DATE(x.updated))
FROM proposal p
JOIN vote v ON p.id = v.p_id
INNER JOIN vote x ON p.id = x.p_id
WHERE DATEDIFF(NOW(), DATE(x.updated)) < 3
GROUP BY p.id
ORDER BY votes DESC;

It's clear that this will return a wrong votes amount as it triples the votes' COUNT(). It's actually 2^n, because it creates a cartesian product just as a CROSS JOIN does.

Is there any way I can get the proper amount without using a subSELECT?

Was it helpful?

Solution

Instead, you can create a kind of COUNTIF function using this pattern:
- COUNT(CASE WHEN <condition> THEN <field> ELSE NULL END)

For example...

SELECT
  p.title,
  COUNT(v.p_id) AS votes,
  COUNT(CASE WHEN v.updated >= DATEADD(DAY, -3, CURRENT_DATE()) THEN v.p_id ELSE NULL END) AS new_votes
FROM
  proposal p
JOIN
  vote     v
    ON p.id = v.p_id
GROUP BY
   p.title
ORDER BY
   COUNT(v.p_id) DESC
;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top