Can I SQL join a table twice?
-
21-12-2019 - |
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 subSELECT
s. So my approach is to fetch by joining the vote
s 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 , 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
?
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
;