Получить даты со значениями, превышающими среднюю ставку заимствования - PullRequest
0 голосов
/ 12 сентября 2018

У меня есть таблица с именем BOOK (memberId, ISBN, dateBorrowed) Например:

   isbn       |    memberId |   borrowed   
-------+---------------+-------------+----
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;

Теперь, как объединить эти два продолжения в одно ясное продолжение?

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Использование оконных функций может вам очень помочь: 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: Этооконная функция подсчитывает все строки, которые равны подсчетам заимствований за все время .

Результат пока выглядит следующим образом:

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
0 голосов
/ 12 сентября 2018

Это немного похоже на HW, поэтому оконные функции могут выходить за пределы.

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...