【问题标题】:How do I get unique user engagements?如何获得独特的用户参与度?
【发布时间】:2023-04-03 18:15:01
【问题描述】:

我正在尝试使用 engagement_type 列出唯一的 user engagements

我曾经有以下查询。

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);

返回:

id        | fname      | lname
------------------------------
1         | joe        | abc
2         | sarah      | qer
3         | megan      | tryey
4         | john       | vdfa

这很好。现在,我想包括参与类型。我想出了这个:

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);

现在返回:

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

上面的唯一问题。结果不再是唯一的。如您所见,Joe 和 Megan 有 2 个条目。

知道如何让它工作吗?

【问题讨论】:

  • 尝试从GROUP BY 子句中删除engagement_type 并检查是否满足您的需求。
  • 然而,joe 有两个独特的约定,即commentlikemegan也是如此。
  • 取决于你想做什么。你想只显示一个engagement_type 还是像“comment, like”这样的列表?
  • 您的 b 子查询被分组为 BY id, engagement_type,这就是为什么每个用户可以获得不止一行的原因。您可以将 LIMIT 更改为 1 以将其更改为仅一行,但您真正想要哪一行(正如 Jakub 所说)?
  • 如果有多个engagement_type,您未能定义要显示的内容。

标签: sql postgresql subquery


【解决方案1】:

在 PostgreSQL 中使用 DISTINCT ON 更简单。
由于缺乏定义,我根据其排序顺序选择第一个 engagement_type

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);

详细信息、链接和说明:

如果您想要一个包含所有参与类型的唯一列表

  SELECT id, string_agg(DISTINCT engagement_type, ', ') AS engagement_types
   FROM (
      ...
      ) a
   GROUP  BY 1
   ORDER  BY <whatever>
   LIMIT  10;

string_agg() 需要 Postgres 9.0 或更高版本。
此表单允许按您想要的任何方式进行排序,而如果您希望 ORDER BY 不同意 DISTINCT ON,则需要另一个子查询。

【讨论】:

  • 非常好的解决方案。欣赏!
  • 只有一件事ORDER BY 在这里是如何工作的?如果我想按最近的约定订购怎么办。我该怎么办?
  • @ChristianFazzini:点击链接。我在应该涵盖它的相关答案中写了一个详细的解释。首先定义“最近的”。问题中没有任何内容可以涵盖这一点。
  • “最新”,按最新参与排序。理想情况下,通过created_at 列。不过,我有点担心。由于created_at 列未编入索引。
【解决方案2】:

如果您只想要一行,则需要从 GROUP BY 子句中删除engagement_type。但是,这不会向您显示所有不同的engagement_type。

如果您想在一行中列出engagement_types 而不复制用户详细信息,请使用ARRAY_TO_STRING 函数。这会将结果污染到一行。因此,您可以将 cmets 表中的参与类型列为逗号分隔列表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-13
    • 1970-01-01
    • 2021-11-04
    • 2021-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多