Sql 为什么在Postgres中没有“选择foo.*…按foo.id分组”?

Sql 为什么在Postgres中没有“选择foo.*…按foo.id分组”?,sql,postgresql,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抱怨我没有在GROUPBY子句中包含foo的所有列。为什么会这样?foo.id是唯一的,这还不够吗?postgresql输出的具体内容是什么?您正在使用聚合函数并尝试输出某些内容 啊。我知道你可能想做什么。使用子选择 select fo

我有这样一个问题:

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

这对SQLite和MySQL非常有效。然而,Postgres抱怨我没有在GROUPBY子句中包含foo的所有列。为什么会这样?foo.id是唯一的,这还不够吗?

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.*您可以使用第二个版本,该版本显式地按所有列分组。

GROUP by子句要求查询返回的每一列要么是GROUP by语句中包含的列,要么是聚合函数,如示例中的COUNT。如果看不到您的GROUPBY子句是什么或foo的列是什么,就很难知道到底发生了什么,但我猜问题是foo.*试图返回一个或多个不在GROUPBY子句中的列


这实际上是SQL的一个通用属性,不应该特定于PostgreSQL。不知道为什么它对SQLite或MySQL有效-可能foo.*中的所有列实际上都在您的GROUP BY子句中,但PostgreSQL无法确定-所以请尝试显式列出foo的所有列。

有些数据库对此比较放松,无论好坏。查询是非特定的,因此结果也是非特定的。如果数据库允许查询,它将从每个组返回一条记录,而不管是哪一条记录。其他数据库更具体,需要您指定要从组中获取的值。他们不允许您编写具有不特定结果的查询

在没有聚合的情况下,您只能选择group by子句中的值:

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

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

以防其他人在这个问题上绊倒:


从PostgreSQL 9.1开始,在group by子句中列出主键的列就足够了,这样问题中的示例现在就可以使用了。

语句中没有group by子句。。。你忘了吗?仅仅因为mysql接受它并不意味着这是一个好主意或一种正确的方法,如果在一个foo的bar中没有任何条目,那么最后一个将不起作用,你必须做:选择foo.*,COALESCEsub.bar\u count from foo left outer join SELECT。。。sub-on-sub.id=foo.id;此外,您不需要在subselect.err.中执行联接。。我的评论版本遗漏了几个字符。我的意思见我上面的答案。从mysql迁移后的整个晚上,我都无法应对pg的这种奇怪行为:Thanx@kovpack当前位置博士后的这种行为并不奇怪。Postgres按照SQL标准和其他数据库管理系统的要求工作。这是MySQL,这是奇怪的,在这里不说破碎
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