如何在Postgres中使用带有通配符的组

时间:2012-04-16 07:34:45

标签: sql postgresql group-by

我在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新手,如果这很明显,请保持温和:)

5 个答案:

答案 0 :(得分:3)

不幸的是,如果不列出useruserprofile中的所有列,我认为您无法做到这一点。 (通常认为使用通配符只是为简单的即席查询做的事情,我想这也是原因之一!)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    

答案 1 :(得分: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等窗函数。

答案 2 :(得分:2)

您正在尝试要求数据库计算一些非常不具体的内容 您想要计算订单,但是您想要显示所有详细信息,如果用户配置文件包含每个用户多行并且这些行不同,那么每个u.id将为您指定多行你只想要一个 这就是为什么数据库在说&#34;走开,告诉我你真正想要的东西&#34;

答案 3 :(得分: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可以促进functional dependencies on primary keys,因此只允许包含GROUP BY子句的主键

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

答案 4 :(得分:1)

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

Starting from version 9.1如果您执行GROUP BY主键列,PostgreSQL也支持您正在寻找的功能。所以升级可能是一个很好的选择。