Группировка SQLite по каждому определенному интервалу

#sql #database #sqlite

#sql #База данных #sqlite

Вопрос:

давайте предположим, что у меня есть таблица с записями, и эти записи содержат столбец timestamp (as Long), который сообщает нам, когда эта запись поступила в таблицу.

Теперь я хочу сделать запрос SELECT, в котором я хочу знать, сколько записей поступило в выбранный интервал с конкретной частотой.

Например: интервал — с 27.10.2020 по 30.10.2020, а частота — 6 часов. Результат запроса сообщит мне, сколько записей поступило за этот интервал в 6-часовых группах.

Нравится:

  • 27.10.2020 00:00:00 — 27.10.2020 06:00:00 : 2 записи
  • 27.10.2020 06:00:00 — 27.10.2020 12:00:00 : 5 записи
  • 27.10.2020 12:00:00 — 27.10.2020 18:00:00 : 0 записи
  • 27.10.2020 18:00:00 — 28.10.2020 00:00:00 : 11 записи
  • 28.10.2020 00:00:00 — 28.10.2020 06:00:00 : 8 записи и т.д…

Параметр частоты может быть вставлен в часах, днях, неделях…

Спасибо всем за помощь!

Ответ №1:

Сначала вам нужен рекурсивный CTE метод, который возвращает временные интервалы:

 with cte as (
  select '2020-10-27 00:00:00' datestart,
         datetime('2020-10-27 00:00:00', ' 6 hour') dateend
  union all
  select dateend,
         min('2020-10-30 00:00:00', datetime(dateend, ' 6 hour'))
  from cte 
  where dateend < '2020-10-30 00:00:00'
)
  

Затем вы должны выполнить LEFT объединение этого CTE с таблицей и агрегировать:

 with cte as (
  select '2020-10-27 00:00:00' datestart,
         datetime('2020-10-27 00:00:00', ' 6 hour') dateend
  union all
  select dateend,
         min('2020-10-30 00:00:00', datetime(dateend, ' 6 hour'))
  from cte 
  where dateend < '2020-10-30 00:00:00'
)
select c.datestart, c.dateend, count(t.datecol) entries
from cte c left join tablename t
on datetime(t.datecol, 'unixepoch') >= c.datestart and datetime(t.datecol, 'unixepoch') < c.dateend
group by c.datestart, c.dateend
  

Замените tablename и datecol именами вашей таблицы и столбца даты.
Если ваш столбец date содержит миллисекунды, измените ON предложение на это:

 on datetime(t.datecol / 1000, 'unixepoch') >= c.datestart 
and datetime(t.datecol / 1000, 'unixepoch') < c.dateend
  

Комментарии:

1. Большое спасибо! Это работает отлично, не могли бы вы, пожалуйста, показать мне, как это можно было бы сделать в PostgreSQL?

2. Вот так: dbfiddle.uk /…

Ответ №2:

Вот один из вариантов:

 select 
    datetime((strftime('%s', ts) / (6 * 60 * 60)) * 6 * 60 * 60, 'unixepoch') newts,
    count(*) cnt
from mytable
where ts >= '2020-10-27' and ts < '2020-10-30'
group by newts
order by newts
  

ts представляет столбец datetime в вашей таблице. У SQLite нет long типа данных, поэтому предполагается, что у вас есть законная дата, сохраненная как text .

Логика запроса состоит в том, чтобы превратить дату в временную метку эпохи, а затем округлить ее до 6 часов, что представлено 6 * 60 * 60 .

Комментарии:

1. Дата сохраняется в таблице как bigint