为什么在Postgres中没有“SELECT foo。* ... GROUP BY foo.id”?

时间:2009-07-16 07:39:30

标签: sql postgresql

我有这样的查询:

select foo.*, count(bar.id)
from foo inner join bar on foo.id = bar.foo_id
group by foo.id

这适用于SQLite和MySQL。然而,Postgres抱怨我没有在group by子句中包含foo的所有列。为什么是这样? foo.id是独一无二的还不够吗?

4 个答案:

答案 0 :(得分:31)

以防万一其他人偶然发现这个问题:

从PostgreSQL 9.1开始,在group by子句中列出主键的列就足够了(因此问题中的示例现在可以正常工作)。

答案 1 :(得分:5)

有些数据库对此更加放松,无论好坏。查询是非特定的,因此结果同样不明确。如果数据库允许查询,它将从每个组返回一条记录,而不关心哪一条记录。其他数据库更具体,需要您指定组中所需的值。他们不会让您编写具有非特定结果的查询。

在没有聚合的情况下,您可以选择的唯一值是group by子句中的值:

select foo.id, count(bar.id)
from foo inner join bar on foo.id = bar.foo_id
group by foo.id

您可以使用聚合来获取其他值:

select foo.id, min(foo.price), count(bar.id)
from foo inner join bar on foo.id = bar.foo_id
group by foo.id

如果你想要foo表中的所有值,你可以将它们全部放在group by子句中(如果这给出了正确的结果):

select foo.id, foo.price, foo.name, foo.address, count(bar.id)
from foo inner join bar on foo.id = bar.foo_id
group by foo.id, foo.price, foo.name, foo.address

或者,您可以使用子查询加入表:

select foo.id, foo.price, foo.name, foo.address, sub.bar_count
from foo
inner join (
   select foo.id, bar_count = count(bar.id)
   from foo inner join bar on foo.id = bar.foo_id
   group by foo.id
) sub on sub.id = foo.id

答案 2 :(得分:3)

你究竟会有什么postgresql输出?您正在使用聚合函数并尝试输出“某些东西”。

阿。我明白你可能想做什么。使用子选择。

select foo.*, (select count(*) from bar where bar.foo_id=foo.id) from foo;

检查说明该计划看起来不错。一个子选择并不总是坏的。我只是检查了我正在使用的数据库,我的执行计划对该查询很有用。

是的,理论上用foo.id分组就足够了(即:你的查询加上“foo.id分组”)。但显然(我测试过)postgresql不会这样做。另一种选择是“按foo.id,foo.foo,foo.bar,foo.baz分组”以及“foo。*”中的所有其他内容。

Guffa所依据的另一种方式是:

SELECT foo.*, COALESCE(sub.cnt, 0)
FROM foo
LEFT OUTER JOIN (
  SELECT foo_id, count(*) AS cnt
  FROM bar
  GROUP BY foo_id) sub
ON sub.foo_id = foo.id;

这将是两个查询(一个子查询,只运行一次),这可能很重要,但可能不会。如果您可以不使用“foo。*”,则可以使用明确按所有列分组的第二个版本。

答案 3 :(得分:1)

GROUP BY子句要求查询返回的每一列都是GROUP BY语句中包含的列或聚合函数(例如示例中的COUNT)。如果没有看到GROUP BY子句是什么或foo的列是什么,很难说出究竟发生了什么,但我猜是问题是foo.*试图返回一个或多个不在GROUP BY子句中的列。

这实际上是SQL的一般属性,不应该特定于PostgreSQL。不知道为什么它适用于SQLite或MySQL - 也许foo.*中的所有列实际上都在你的GROUP BY子句中但是PostgreSQL无法解决这个问题 - 所以尝试列出所有的明确列foo