如何提取 postgresql 中 ~120k 行总和的最大值?

How to extract the max of the sum of ~120k rows in postgresql?

我有一个自行车商店的数据库,table 我打电话给 "SalesOrderHeader" 其中包括以下 2 列:CustomerIDTotalDue

它包含有关自行车商店所有销售的信息。所以如果f.e。一个顾客在商店里总共买了 2 次,他的 CustomerID 会有 2 个记录,每次他支付的金额 (TotalDue)。

如何编写一个 select 查询来显示支付总额最高的 1 个(或多个,如果是平局)客户。结果必须显示 2 列,一列带有 CustomerID,一列带有 TotalMoneyHePaid

您可以在 HAVING 子句中使用子查询来获取:

SELECT customerid,
    sum(totaldue)
FROM SalesOrderHeader
GROUP BY customerid
HAVING sum(totaldue) = (
        SELECT sum(totaldue)
        FROM SalesOrderHeader
        GROUP BY customerID
        ORDER BY sum(totalDue) DESC LIMIT 1
        )

子查询:

    SELECT sum(totaldue)
    FROM SalesOrderHeader
    GROUP BY customerID
    ORDER BY sum(totalDue) DESC LIMIT 1

通过按 sum(totaldue) 排序记录然后仅保留第一条记录 LIMIT 1 来获得最大客户的 sum(totalDue)。我们在 HAVING 子句中使用它来将其与每个客户的 Sum(totaldue) 进行比较。如果主查询中的客户有一个 sum(totaldue) 相当于子查询的结果,那么我们保留记录。

postgres=> CREATE TABLE salesorderheader
postgres-> (
postgres(>   customerid integer,
postgres(>   totaldue integer
postgres(> );
CREATE TABLE

postgres=> INSERT INTO salesorderheader VALUES
postgres->   (1, 10),
postgres->   (1, 12),
postgres->   (2, 22),
postgres->   (3, 5),
postgres->   (4, 4);
INSERT 0 5

postgres=> SELECT customerid, sum(totaldue) FROM SalesOrderHeader GROUP BY customerid HAVING sum(totaldue) = (SELECT sum(totaldue) FROM SalesOrderHeader GROUP BY customerID ORDER BY sum(totalDue) desc LIMIT 1);
 customerid | sum
------------+-----
          1 |  22
          2 |  22
(2 rows)

我建议在子查询中对 totaldue 的总和使用 window function rank()

SELECT customerid, total_money_paid
FROM  (
   SELECT customerid, sum(totaldue) AS total_money_paid
        , rank() OVER (ORDER BY sum(totaldue) DESC NULLS LAST) AS rnk
   FROM   salesorderheader
   GROUP  BY 1
   ) sub
WHERE  rnk = 1;

这样,table 只被扫描 一次 。应该更快。 Window 函数在 普通聚合函数之后计算,因此这是可能的。相关:

  • Postgres window function and group by exception

NULLS LAST 只有当总和可以是 NULL 时才需要(即 totaldue 可以是 NULL)。详情:

  • PostgreSQL sort by datetime asc, null first?

我选择这个技术是因为你的要求:

show the 1 (or more, in case of a tie) customer

如果你想要正好 1(以某种方式打破关系,如果有更多),那么DISTINCT ON会更可取:

  • Select first row in each GROUP BY group?