4

我在 Postgres 中遇到了这段代码的问题。我想获取用户表中的所有字段,但只能按 id 分组。这在 MySQL 和 SQLite 上运行良好,但在谷歌搜索后我发现这种行为不是标准的一部分。

SELECT u.*, p.*, count(o.id) AS order_count
FROM shop_order AS o
LEFT JOIN user AS u ON o.user_id = u.id
LEFT JOIN userprofile AS p ON p.user_id = u.id
WHERE o.shop_id = <shop_id>
GROUP BY u.id

(请注意,它<shop_id>是以编程方式传递的,因此您可以轻松地将其替换为任何整数。)

这是我得到的错误

column "u.id" must appear in the GROUP BY clause or be used in an aggregate function

我是 SQL 新手,所以如果这很明显,请保持温和 :)

4

5 回答 5

4

user不幸的是,如果不列出 和 中的所有列,我认为您无法做到这一点userprofile。(通配符的使用通常被认为是你只为简单的临时查询所做的事情,我想这是原因之一!) MySQL 和其他数据库有一个“方便”的特性,如果一个列都不在 GROUP BY 子句或聚合函数中,则每个组中该列的任何值都可以显示在结果中。PostgreSQL 有点严格。

但通常情况下,表中只有几列就足够分组了。有很多方法可以重写它。也许您可以做的是:

SELECT u.*, p.*, (select count(o.id) FROM shop_order AS o WHERE o.user_id = u.id AND o.shop_id = <shop_id>) AS order_count
FROM user AS u
LEFT JOIN userprofile AS p ON p.user_id = u.id    
于 2012-04-16T07:44:36.663 回答
2

您可以使用row_number将结果限制为每个用户一行:

select  *
from    (
        select  row_number() over (partition by u.id) as rn
        ,       *
        join    user u
        on      sub.user_id = u.id
        join    shop_order so
        on      so.user_id = u.id
        left join
                userprofile up
        on      up.user_id = u.id
        where   so.shop_id = <shop_id>
        ) as SubQueryAlias
where   rn = 1

子查询是必需的,因为 Postgres 不允许像子句row_number中那样的窗口函数。where

于 2012-04-16T07:44:13.127 回答
2

您正试图要求数据库计算一些非常不具体的东西您想计算订单但又想显示所有详细信息,如果用户配置文件包含每个用户的多行并且这些行不同,该怎么办,对于每个 u.id,您将获得不止一行,并且您指定您只想要一个这就是为什么数据库说“走开,告诉我你真正想要什么”

于 2012-04-16T07:55:43.207 回答
2

你的 Postgres 版本是什么?如果您使用 Postgres 9.0 及以下版本,您的代码构造将不会运行。例如,这是不允许的:

SELECT
    p.id,
    p.firstname, p.lastname, p.address, -- these auxiliary fields is helpful to program users
    count(*)
FROM
    people p
    JOIN visits v ON p.id = v.person_id
GROUP BY p.id

必须在 9.0 及以下版本上执行此操作:

SELECT
    p.id,
    p.firstname, p.lastname, p.address, -- these auxiliary fields is helpful to program users
    count(*)
FROM
    people p
    JOIN visits v ON p.id = v.person_id
GROUP BY p.id
    ,p.firstname, p.lastname, p.address; -- these ancillary fields aids the RDBMS on preventing
    -- programmers from accidentally committing the same mistake as MySQL programmers.

如果您使用的是 Postgres 9.1,您当然可以在 GROUP BY 中只使用一个字段,即使您在 SELECT 子句中有很多字段,只要该 GROUPed 字段是主键。因此这将运行:

SELECT
    p.id,
    p.firstname, p.lastname, p.address, -- these auxiliary fields is helpful to program users
    count(*)
FROM
    people p
    JOIN visits v ON p.id = v.person_id
GROUP BY p.id 
-- note that there's no need to repeat the SELECTed fields on GROUP BY clause

Postgres 9.1 可以促进对主键的功能依赖,因此只允许在 GROUP BY 子句中包含主键

SQL 小提琴示例:http ://sqlfiddle.com/#!1/3b857/3

于 2012-04-16T07:58:54.080 回答
2

您使用的是哪个版本的 PostgreSQL?我相信它是 9.1 之前的版本。

从 9.1 版开始, PostgreSQL 还支持您正在寻找的功能,以防您使用GROUP BY主键列。所以也许升级是一个不错的选择。

于 2012-04-16T08:10:53.483 回答