【问题标题】:How to aggregate on first value in postgres sql?如何聚合postgresql中的第一个值?
【发布时间】:2016-05-09 04:43:08
【问题描述】:

在这个 postgres 查询中

SELECT
    q.*,
    q.user_id = 1 mine,
    first(u.username) username,
    sum(case when v.answer=0 then 1 else 0 end) no_count,
    sum(case when v.answer=1 then 1 else 0 end) yes_count
FROM question q 
JOIN "user" u ON q.user_id=u.id
JOIN vote v ON v.question_id=q.id
GROUP BY q.id
ORDER BY q.date_created desc 
LIMIT 20
OFFSET 0

它说我需要username 上的聚合。在这种情况下,我收到问题,每个问题都是由某个用户创建的。我加入投票,但按问题 id 分组,因此在分组之前,每个唯一问题的用户名字段都是相同的。所以这意味着在聚合时,我真的可以选择任何值,因为它都是一样的。但是我找不到任何要使用的聚合函数。我尝试了随机、第一个、最后一个、任何一个,但都没有工作,甚至没有定义。

有人知道怎么处理吗?

【问题讨论】:

  • 只需将username 添加到group by 子句,根本不要聚合。

标签: postgresql group-by


【解决方案1】:

好的,问题是sql引擎不知道username总是一样的。换句话说,它无法区分guestions 和users 之间的一对一关系和一对多关系。您可以将string_agg() 与DISTINCT 一起使用,例如string_agg(DISTINCT u.username, ','::text)。该函数的作用是将文本值聚合成一个由指定分隔符分隔的大字符串(在我的情况下为逗号)。当您添加 DISTINCT 时,它只需要唯一值。由于您说过每个问题始终只有一个用户名,因此输出将是该单个值。

整个查询:

SELECT
    q.*,
    q.user_id = 1 mine,
    string_agg(DISTINCT u.username, ','::text) username,
    sum(case when v.answer=0 then 1 else 0 end) no_count,
    sum(case when v.answer=1 then 1 else 0 end) yes_count
FROM question q 
JOIN "user" u ON q.user_id=u.id
JOIN vote v ON v.question_id=q.id
GROUP BY q.id
ORDER BY q.date_created desc 
LIMIT 20;

脚注:我删除了 OFFSET 0,因为它是 LIMIT 的默认值。

【讨论】:

    【解决方案2】:

    从框 postgresql 不允许或不能执行此类操作,但有解决方法。

    您可以通过此方法扩展聚合函数 First/Last:https://wiki.postgresql.org/wiki/First/last_(aggregate)

    postgresql 有插件和可移植的 sql 版本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-06
      • 1970-01-01
      • 1970-01-01
      • 2022-01-19
      • 2022-07-27
      • 2018-01-14
      相关资源
      最近更新 更多