问题
I am trying to list unique user engagements
with the engagement_type
I used to have the following query.
SELECT u.id, u.fname, u.lname FROM (
SELECT id, engagement_type FROM (
SELECT user_id AS id, 'comment'
FROM comments WHERE commentable_id = 48136 AND commentable_type = 'Video'
UNION ALL
SELECT user_id AS id, 'like'
FROM likes WHERE likeable_id = 48136 AND likeable_type = 'Video'
) AS a
GROUP BY id
LIMIT 10
) b JOIN users u USING (id);
Returns:
id | fname | lname
------------------------------
1 | joe | abc
2 | sarah | qer
3 | megan | tryey
4 | john | vdfa
Which is fine. Now, I want to include the engagment type. I've come up with this:
SELECT u.id, u.fname, u.lname, engagement_type FROM (
SELECT id, engagement_type FROM (
SELECT user_id AS id, 'comment' AS engagement_type
FROM comments WHERE commentable_id = 48136 AND commentable_type = 'Video'
UNION ALL
SELECT user_id AS id, 'like' AS engagement_type FROM likes
WHERE likeable_id = 48136 AND likeable_type = 'Video'
) AS a
GROUP BY id, engagement_type
LIMIT 10
) b JOIN users u USING (id);
Which now returns:
id | fname | lname | engagement_type
---------------------------------------------------
1 | joe | abc | comment
2 | sarah | qer | like
3 | megan | tryey | like
4 | john | vdfa | like
1 | joe | abc | like
3 | megan | tryey | comment
The only problem with above. The results are not unique anymore. As you can see, Joe and Megan have 2 entries.
Any idea how I can get this to work?
回答1:
Simpler with DISTINCT ON
in PostgreSQL.
For lack of definition I pick the first engagement_type
according to its sort order:
SELECT u.id, u.fname, u.lname, b.engagement_type
FROM (
SELECT DISTINCT ON (1)
id, engagement_type
FROM (
SELECT user_id AS id, 'comment' AS engagement_type
FROM comments
WHERE commentable_id = 48136
AND commentable_type = 'Video'
UNION ALL
SELECT user_id, 'like'
FROM likes
WHERE likeable_id = 48136
AND likeable_type = 'Video'
) a
ORDER BY 1, 2
LIMIT 10
) b
JOIN users u USING (id);
Details, links and explanation:
- Select first row in each GROUP BY group?
If you want a unique list of all engagement_types:
SELECT id, string_agg(DISTINCT engagement_type, ', ') AS engagement_types
FROM (
...
) a
GROUP BY 1
ORDER BY <whatever>
LIMIT 10;
string_agg() need Postgres 9.0 or later.
This form allows to order by whatever you want, while you'd need another subquery if you want ORDER BY
to disagree with DISTINCT ON
.
回答2:
If you want only one row you need to remove the engagement_type from the GROUP BY clause. however this then won't show you all the different engagement_type's.
If you want to list the engagement_types in one row without duplicating the user details then use the ARRAY_TO_STRING function. This contaminates the results to one line. So you could list the engagement types from the comments table as a comma separated list.
来源:https://stackoverflow.com/questions/15186763/how-do-i-get-unique-user-engagements