【问题标题】:SQL Select rows with max difference on a columnSQL选择列上差异最大的行
【发布时间】:2019-04-07 04:38:34
【问题描述】:

我有两个 Postgres 表,如下所示,分别称为 client 和 order。

id | name
------------
41 | james
29 | melinda
36 | henry
...

id | date | volume | client_id
------------------------------
328 | 2018-01-03 | 16 | 41
411 | 2018-01-29 | 39 | 29
129 | 2018-01-13 | 73 | 29
542 | 2018-01-22 | 62 | 36
301 | 2018-01-17 | 38 | 41
784 | 2018-01-08 | 84 | 29
299 | 2018-01-10 | 54 | 36
300 | 2018-01-10 | 18 | 36
178 | 2018-01-30 | 37 | 36
...

然后我用以下逻辑写了一个查询:

i) 找出每个订单与其前一个订单之间的交易量差异,按每个客户和订单按日期分组。对于第一个订单,此列将为空。

ii) 显示客户以及每个客户的最大音量差异。

with cte AS
  (SELECT t.name,
          t.date,
          t.volume,
          t.volume - lag(t.volume) over (
                                         ORDER BY t.name, t.date) AS change
   FROM
     (SELECT c.name,
             o.date,
             sum(o.volume) volume
      FROM orders o
      JOIN client c using (client_id)
      GROUP BY c.name,
               o.date
      ORDER BY c.name,
               o.date) t)
SELECT cte.name,
       max(abs(change))
FROM cte
GROUP BY name

下面是结果表。

name | max
------------
james   | 22
melinda | 34
henry   | 25

我希望就三件事获得建议。

a) 是否可以用符号表示差异?对于客户端 ID 29 和 36,值应分别为 -34 和 -25。

b) 是否也可以显示日期?我尝试在 CTE 上选择日期列,但没有成功。

c) 有人对我如何改进查询以使其更具性能或可读性有任何一般性建议吗?

【问题讨论】:

    标签: sql postgresql subquery greatest-n-per-group window-functions


    【解决方案1】:

    Postgres 支持DISTINCT ON,确实方便你查询。此外,您可以简化查询,因为窗口函数和聚合函数可以在同一级别上组合:

    SELECT DISTINCT ON (co.name) co.*
    FROM (SELECT c.name, o.date, SUM(o.volume) as volume,
                 LAG(SUM(o.volume)) OVER (PARTITION BY c.name ORDER BY o.date) as prev_volume
          FROM orders o JOIN
               client c 
               USING (client_id)
          GROUP BY c.name, o.date
         ) co
    ORDER BY c.name, ABS(volume - prev_volume) DESC
    

    【讨论】:

      【解决方案2】:

      感谢 Gordon Linoff 对这个查询的大部分内容,但是它需要一些调整,特别是下面看到的 where 子句。

      SELECT DISTINCT ON (co.name) 
             co.client_id
           , co.name
           , co.DATE
           , (co.volume - co.prev_volume) change
      FROM (
           SELECT 
                  c.client_id
                , c.name
                , o.DATE
                , SUM(o.volume) AS volume
                , LAG(SUM(o.volume)) OVER (PARTITION BY c.name 
                                           ORDER BY o.DATE) AS prev_volume
           FROM orders o
           INNER JOIN client c USING (client_id)
           GROUP BY
                 c.client_id
                , c.name
                , o.DATE
           ) co
      WHERE prev_volume IS NOT NULL
      ORDER BY
             co.name
           , ABS(co.volume - co.prev_volume)  DESC
      

      结果:

      客户 ID |姓名 |日期 |改变 --------: | :-------- | :--------- | -----: 36 |亨利 | 2018-01-30 | -25 41 |詹姆斯 | 2018-01-17 | 22 29 |梅琳达 | 2018-01-29 | -34

      db小提琴here

      【讨论】:

      • 感谢这个很棒的查询,但我想详细说明我的问题。我不想显示最近两个订单之间的交易量差异,而是想显示从一个订单到下一个订单的最大交易量变化。它不必是最近的两个。
      • 例如,如果我在订单表431 | 2018-01-30 | 20 | 29 中添加一行,则最终表中client_id 29 的更改将更改为-19,而它应该保持在-34。
      • 并且日期应该相应改变,而不是显示最近一次订单的日期。
      • 请注意,上面的查询实际上只是 Gordon Linoff 查询的一个小修改,我原以为您追求的是不同的东西,但在您的 cmets 之后,我唯一实质性的补充是 where 子句。跨度>
      猜你喜欢
      • 1970-01-01
      • 2021-10-20
      • 1970-01-01
      • 2021-08-16
      • 2011-12-06
      相关资源
      最近更新 更多