使用 CASE WHEN 从不同的行获取不同的值

Getting separate values from separate rows using CASE WHEN

我有一个数据集,其中用户有 2 个操作,一个有用的操作和一个无用的操作:

user_id | action_id | useful
   1    |     3     |  True
   1    |     4     |  False
   2    |     5     |  True

我想要一个显示用户 ID 以及他们在同一行上执行的有用和无用操作的 ID 的数据集。像这样:

user_id | useful_action_id | not_useful_action_id
   1    |       3          |         4
   2    |       5          |       NULL

我试过以下方法:

SELECT
    user_id,
    case when useful = True then action_id else null end,
    case when useful = False then action_id else null end
FROM actions
GROUP BY user_id

但有人告诉我:

Error running query: column "useful" must appear in the `GROUP BY` clause or be used in an aggregate function

但是不,我特别不希望 'useful' 出现在 GROUP BY 中,对吗?我只想将它按 user_id

分组

您正在使用 GROUP BY,但未执行聚合。看起来您正在尝试条件聚合并且您非常接近。您只需要使用聚合函数,如下所示:

SELECT
    user_id,
    max(case when useful = True then action_id end) AS useful_action_id,
    max(case when useful = False then action_id end) AS not_useful_action_id
FROM actions
GROUP BY user_id

如果您希望每个用户都有 "useful" 和 "not useful" ID,请使用 array_agg() 聚合函数:

select
    user_id,
    array_agg(action_id) filter (where useful) as useful_action_ids,
    array_agg(action_id) filter (where not useful) as not_useful_action_ids
from actions
group by 1;

一些补充意见:

  • 如果在组中没有找到ID,它将输出空数组({}),而不是NULL。如果确实需要 NULL,请添加 case/when 表达式。
  • 如果 useful 列中有 NULL,上面的查询将不会采用它们。在这种情况下,如果您确实希望将此类 NULL 视为 "not useful",只需使用 (where not coalesce(useful, false))。但是您可能更喜欢多一组 ID,例如 usefulness_is_not_clearfilter (where useful is null) :)