postgreSQL 选择聚合函数中未使用的附加列

Posted

技术标签:

【中文标题】postgreSQL 选择聚合函数中未使用的附加列【英文标题】:postgreSQL select additional columns that aren't used in aggregate function 【发布时间】:2011-06-12 22:25:50 【问题描述】:

我正在尝试在 PostgreSQL 中编写一个查询,但我有点沮丧,因为它适用于其他数据库引擎。我需要从给定的联接表中选择前 5 个用户,如下所示:

选择用户。*, COUNT(deals.id) AS num_deals 来自用户,交易 WHERE deal.users_id = users.id GROUP BY users.id 按 num_deals 限制 5 订购;

我需要前 5 名用户。此代码适用于 sqlite、mysql 等,但 PostgreSQL 拒绝选择未在聚合函数中使用的其他字段。我收到以下错误:

PGError: ERROR:  column "users.id" must appear in the GROUP BY clause or be used in an aggregate function

如何在 PostgreSQL 中做到这一点?

【问题讨论】:

我相信它在 MySQL 和 SQLite 中有效,但“etc”是错误的。没有其他数据库允许这样做。只有这两个。 其实,假设 users.id 是 PRIMARY KEY,它没有错。 (尽管例如 MySQL 在正确和错误时都会这样做)。 PostgreSQL 9.1 将支持以编写方式运行此查询 - 因为 GROUP BY 在 PRIMARY KEY 上,我们可以推断所有其他列在功能上都依赖于它。 @Magnus:我知道9.1会支持这个,但是9.1目前不可用 @horse:绝对正确。但他们错误的说法部分(尽管只是部分)不正确。 @MagnusHagander:你知道为什么需要 PRIMARY KEY 而不仅仅是 UNIQUE 吗?我无法想象唯一性不够好的情况。 【参考方案1】:

以防万一有人想要 ANSI-92 标准解决方案并且不喜欢“Oracle”连接表的方式...

SELECT users.*, num_deals
FROM users
JOIN
  (SELECT deals.users_id as users_id, count(deals.users_id) as num_deals
   FROM deals
   GROUP BY deals.id) grouped_user_deals
ON grouped_user_deals.users_id = users.id
ORDER BY num_deals DESC
LIMIT 5;

【讨论】:

【参考方案2】:

另一个可行的解决方案是在 GROUP BY 中隐式使用所有属性

因此以下将是最终查询

SELECT users.*, 
       COUNT(deals.id) AS num_deals 
FROM users, deals 
WHERE deals.users_id = users.id 
GROUP BY users.id, users.name, users.attrib1, ..., users.attribN
ORDER BY num_deals LIMIT 5;

如果您使用的是像 rails 这样的框架,那么您可以使用 Model.column_names 函数轻松实现这一点。

【讨论】:

【参考方案3】:

假设 users.id 是一个 PK,那么你可以

等待 9.1

按所有字段分组

在所有字段上使用聚合(即 max() )

【讨论】:

使用 max() - 低速 使用distinct on:select distinct on (col1, col2) col1, col2, col3, col4 from yada;【参考方案4】:

你可以试试:

SELECT users.*, a.num_deals FROM users, (
    SELECT deal.id as dealid, COUNT(deals.id) AS num_deals 
    FROM deals 
    GROUP BY deal.id
) a where users.id = a.dealid
ORDER BY a.num_deals DESC
LIMIT 5

【讨论】:

+1 表示跨 dbms 解决方案。但是第一行 users 后面的逗号是错误的,应该按 num_deals DESC 排序 您不能删除子查询中对“用户”表的引用吗?这样它只会查看每个表一次。 @a_horse_with_no_name:您对 ORDER BY 的看法是正确的。 ...起初我认为您对第一行中的逗号是正确的,但我认为它实际上是正确的(它将用户表与子查询/a 表分开) @araqnid:我已经实现了你的建议。谢谢。 @Gerrat:啊,你对逗号的看法是正确的。我不习惯那种老式的连接,我总是使用 JOIN ... ON 语法。抱歉打扰了

以上是关于postgreSQL 选择聚合函数中未使用的附加列的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL - 从连接表中选择聚合列并使用它来求和

Postgresql 错误:列必须出现在 GROUP BY 子句中或在聚合函数中使用

Django 与 Postgresql,列必须出现在 GROUP BY 子句中或在聚合函数中使用

Postgresql“列必须出现在 GROUP BY 子句中或在聚合函数中使用”和唯一字段

PostgreSQL 调用函数返回带有表和附加列的记录集

PostgreSQL 9.6 在对时间戳列进行聚合期间选择了错误的计划