【问题标题】:Calculate difference of multiple highest and lowest column values计算多个最高和最低列值的差异
【发布时间】:2021-03-10 22:11:38
【问题描述】:

我有一张这样的桌子:

id | name | salary
------------------
1  | guy1 | 1000
2  | guy2 | 750
3  | guy3 | 400
4  | guy4 | 1000
5  | guy5 | 925
6  | guy6 | 900

我需要取最高工资(本例中为 2 * 1000)和最低工资(本例中为 1 * 400),并返回最高和最低之间的差值,计算如下:

1000 * 2 - 400 * 1 = 1600

difference
----------
1600

我试图过滤工资最高和最低但失败的表。

如果表为空,则结果应为 0。

【问题讨论】:

    标签: sql postgresql select greatest-n-per-group


    【解决方案1】:

    你可以这样做:

    select
      (select sum(salary) from t where salary = (select max(salary) from t))
      -
      (select sum(salary) from t where salary = (select min(salary) from t));
    

    结果:

    1600
    

    请参阅DB Fiddle 的运行示例。

    【讨论】:

    • 感谢您的回答。几乎是对的,期待count(*) * sum(salary)。我将其更改为count(*) + sum(salary),它给了我几乎正确的答案,而不是 1600,它给了我 1601。如果是空表,它应该输出 0。
    • @MikeEhrmantraut - 已修复。如您所见,答案实际上更简单。
    【解决方案2】:

    您可以使用dense_rank 找到最低和最高薪水,然后将这些结果自连接,相加,然后相减:

    SELECT SUM(CASE sal_desc WHEN 1 THEN salary END) - 
           SUM(CASE sal_asc WHEN 1 THEN salary END)
    FROM   (SELECT salary, 
                   DENSE_RANK() OVER (ORDER BY salary ASC)  AS sal_asc,
                   DENSE_RANK() OVER (ORDER BY salary DESC) AS sal_desc
            FROM   mytable) t
    

    【讨论】:

      【解决方案3】:

      一种方法是聚合两次:

      select sum(case when seqnum_desc = 1 then sum_salary
                      else - sum_salary
                 end) as diff
      from (select salary, sum(salary) as sum_salary,
                   row_number() over (order by salary asc) as seqnum_asc,
                   row_number() over (order by salary desc) as seqnum_desc
            from t
            group by salary
           ) t
      where 1 in (seqnum_asc, seqnum_desc)
      

      【讨论】:

        【解决方案4】:

        Postgres 13 添加了 WITH TIES 子句以包含第 n 行的所有对等点:

        如果您在salary 上有索引,这将尽快。比涉及窗口函数快得多:

        SELECT COALESCE(sum(salary), 0) AS diff
        FROM  (
           (  -- parentheses required
           SELECT salary
           FROM   tbl
           ORDER  BY salary DESC
           FETCH  FIRST 1 ROWS WITH TIES
           )
           UNION ALL
           (
           SELECT salary * -1
           FROM   tbl
           ORDER  BY salary
           FETCH  FIRST 1 ROWS WITH TIES
           )
           ) sub;
        

        db小提琴here

        Postgres 可以直接从(salary) 的索引中获取第一个和最后一个值。准即时结果,无论表格有多大。

        COALESCE() 在表为空时获取0 而不是NULL

        为什么要多出括号? The manual:

        (ORDER BYLIMIT 可以附加到子表达式,如果它是 括在括号中。没有括号,这些子句将是 应用于UNION 的结果,而不是应用于其右侧输入 表达。)

        见:

        这是假设salaryNOT NULL,否则将NULLS LAST 附加到降序。见:

        【讨论】:

          猜你喜欢
          • 2016-08-16
          • 1970-01-01
          • 1970-01-01
          • 2018-04-19
          • 2021-06-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-08
          • 2012-12-22
          相关资源
          最近更新 更多