SQL: группировка по точным строкам - PullRequest
0 голосов
/ 10 июля 2020

Допустим, есть схема:

|date|value|

СУБД - это SQLite.

Я хочу получить N групп и вычислить AVG (значение) для каждой из них.

Пример:

2020-01-01 10:00|2.0
2020-01-01 11:00|2.0
2020-01-01 12:00|3.0
2020-01-01 13:00|10.0
2020-01-01 14:00|2.0
2020-01-01 15:00|3.0
2020-01-01 16:00|11.0
2020-01-01 17:00|2.0
2020-01-01 18:00|3.0

Результат (N = 3):

2020-01-01 11:00|7.0/3
2020-01-01 14:00|15.0/3
2020-01-01 17:00|16.0/3

Мне нужно использовать оконную функцию, например NTILE, но кажется, что NTILE нельзя использовать после GROUP BY . Он может создавать сегменты, но тогда как я могу использовать эти сегменты для агрегирования?

SELECT
   /*AVG(*/value/*)*/,
   NTILE (3) OVER (ORDER BY date) bucket
FROM
   test
/*GROUP BY bucket*/
/*GROUP BY NTILE (3) OVER (ORDER BY date) bucket*/

Также отбросил тестовые данные и этот запрос в DBFiddle .

Ответы [ 2 ]

1 голос
/ 10 июля 2020

Мне нужно использовать оконную функцию, например NTILE, но кажется, что NTILE нельзя использовать после GROUP BY. Он может создавать сегменты, но тогда как я могу использовать эти сегменты для агрегации?

Сначала вы используете NTILE для присвоения номеров сегментов в подзапросе, а затем группируете по нему во внешнем запросе.

Использование подзапроса

SELECT bucket
     , AVG(value) AS avg_value
  FROM ( SELECT value
              , NTILE(3) OVER ( ORDER BY date ) AS bucket
           FROM test
       ) x
 GROUP BY bucket
 ORDER BY bucket

Использование предложения WITH

WITH x AS (
   SELECT date
        , value
        , NTILE(3) OVER ( ORDER BY date ) AS bucket
     FROM test
)
SELECT bucket
     , COUNT(*) AS bucket_size
     , MIN(date) AS from_date
     , MAX(date) AS to_date
     , MIN(value) AS min_value
     , AVG(value) AS avg_value
     , MAX(value) AS max_value
     , SUM(value) AS sum_value
  FROM x
 GROUP BY bucket
 ORDER BY bucket
1 голос
/ 10 июля 2020

Вы можете использовать функцию окна NTILE() для создания групп и агрегирования:

SELECT 
  DATETIME(MIN(DATE), ((STRFTIME('%s', MAX(DATE)) - STRFTIME('%s', MIN(DATE))) / 2) || ' second') date, 
  ROUND(AVG(value), 2) avg_value
FROM (
  SELECT *, NTILE(3) OVER (ORDER BY date) grp
  FROM test
) 
GROUP BY grp;

Чтобы изменить количество строк в каждом сегменте, вы должны изменить число 3 в круглых скобках NTILE() .

См. Демонстрацию . Результатов:

| date                | avg_value |
| ------------------- | --------- |
| 2020-01-01 11:00:00 | 2.33      |
| 2020-01-01 14:00:00 | 5         |
| 2020-01-01 17:00:00 | 5.33      |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...