【问题标题】:Get dates with values greater than average borrow rate获取值大于平均借款利率的日期
【发布时间】:2019-02-17 09:50:19
【问题描述】:

我有一个名为BOOK 的表(memberId、ISBN、dateBorrowed) 例如:

 isbn |会员ID |借来的
-------+---------------+----------------+----
9998-01-101-9 | |
9998-01-101-9 | |
9998-01-101-9 | |
9998-01-101-9 | 1000 | 2018-10-02
9998-01-101-9 | 1010 | 2018-09-04
9998-01-101-9 | 1021 | 2018-09-14
9998-01-101-9 | |
9998-01-101-9 | 1001 | 2018-10-02

我必须选择所有dates,其中每天的借书总数大于平均每天的借书数量。怎么做?

我已经选择了日期以及它被选择了多少次:

SELECT borrowed, COUNT(*) AS dates 
  FROM BOOK
  WHERE borrowed IS NOT NULL
  GROUP BY borrowed;

我写的另一个查询是计算平均值:

SELECT SUM(dates)/COUNT(borrowed) AS average 
  FROM (
    SELECT borrowed, COUNT(*) AS dates 
      FROM BOOKS
      WHERE borrowed IS NOT NULL GROUP BY borrowed
  ) AS average;

现在,如何将这两个续集连接成一个清晰的续集?

【问题讨论】:

  • 欢迎来到 SO。我们是来帮助的,而不是为你做你的工作。表明您为解决自己的问题付出了一些努力。
  • 通过编写 sql 查询 :) 到目前为止您尝试过什么?出了什么问题?
  • 我已经选择了日期以及它被选择了多少次:SELECT borrowed, COUNT(*) AS dates FROM WHERE BHERE IS NOT NULL GROUP BY borrowed;
  • 更新了我所做的描述。

标签: sql postgresql


【解决方案1】:

使用窗口函数对你有很大帮助:https://www.postgresql.org/docs/current/static/tutorial-window.html

demo: db<>fiddle

我的测试数据:

isbn             borrowed
9998-01-101-1    2018-08-01
9998-01-101-2    2018-08-01
9998-01-101-3    2018-08-01
9998-01-101-4    2018-08-01
9998-01-101-5    2018-08-01
9998-01-101-1    2018-08-02
9998-01-101-2    2018-08-02
9998-01-101-3    2018-08-02
9998-01-101-4    2018-08-03
9998-01-101-5    2018-08-03
9998-01-101-1    2018-08-04
9998-01-101-2    2018-08-04
9998-01-101-3    2018-08-04
9998-01-101-4    2018-08-04
9998-01-101-5    2018-08-05
9998-01-101-1    2018-08-05

查询:

   SELECT 
        * 
    FROM (
        SELECT 
            *, 
            borrowed_all_time::decimal / COUNT(*) OVER () as avg_borrows_per_day    -- D
        FROM (
            SELECT DISTINCT                                                         -- C
                borrowed,
                COUNT(*) OVER (PARTITION BY borrowed) as borrowed_on_day,           -- A
                COUNT(*) OVER () as borrowed_all_time                               -- B
            FROM book
        )s 
    )s
    WHERE borrowed_on_day > avg_borrows_per_day                                     -- E

A:此窗口函数计算每个 borrowed 日期的行数

B:这个窗口函数计算所有行,等于count borrows of all time

目前的结果如下所示:

borrowed      borrowed_on_day   borrowed_all_time
2018-08-01    5                 16
2018-08-01    5                 16
2018-08-01    5                 16
2018-08-01    5                 16
2018-08-01    5                 16
2018-08-02    3                 16
2018-08-02    3                 16
2018-08-02    3                 16
2018-08-03    2                 16
2018-08-03    2                 16
2018-08-04    4                 16
2018-08-04    4                 16
2018-08-04    4                 16
2018-08-04    4                 16
2018-08-05    2                 16
2018-08-05    2                 16

C:因为我们不需要重复,所以我们用 DISTINCT 消除它们

D:在消除所有并列的行后计算所有行,得出不同天数。这种划分所有时间的借款给出了每天的平均借款decimal 演员表是必要的。它将整数除法 (16 / 5 == 3) 转换为浮点除法 (16 / 5 == 3.2)

E:现在我们可以过滤每天的借款 > 每天的平均借款

结果:

borrowed
2018-08-01
2018-08-04

【讨论】:

    【解决方案2】:

    这看起来有点像硬件,所以窗口函数可能超出范围。

    SELECT * 
      FROM (
        SELECT BOOK.*,
               CAST(
               COUNT(1) OVER 
                 ( PARTITION BY borrowed
                 ) AS FLOAT) cntThatDay,
               CAST(
               SUM(1) OVER() AS FLOAT)/ CAST(
                   (SELECT COUNT(DISTINCT borrowed)
                      FROM BOOKS 
                   ) AS FLOAT) AS totalAverage
          FROM BOOK 
         WHERE borrowed IS NOT NULL
        ) TMP
    WHERE cntThatDay >= totalAverage;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-04
      • 2019-01-13
      • 2012-10-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多