【问题标题】:How to select data with an unusual grouping by date?如何选择按日期分组异常的数据?
【发布时间】:2022-01-01 16:25:59
【问题描述】:

有一张桌子:

id direction_id created_at
1 2 22 November 2021 г., 16:00:00
2 2 22 November 2021 г., 16:20:00
43 2 22 November 2021 г., 16:25:00
455 1 22 November 2021 г., 16:27:00
6567 2 22 November 2021 г., 17:36:00
674556 2 22 November 2021 г., 20:01:00
5243554 1 22 November 2021 г., 20:50:00
5243554 1 22 November 2021 г., 21:46:00

我需要得到以下结果:

1 2 created_at_by_hour
1 3 22.11.21 17
1 4 22.11.21 18
1 4 22.11.21 19
1 4 22.11.21 20
2 5 22.11.21 21
3 5 22.11.21 22

标题中的 1 和 2 是表中 direction_id 的所有可能值。 created_at 减少到小时,您需要计算有多少记录满足条件 created_at_by_hour。但是分组应该是这样的,如果没有创建记录的时间(小时),那么只需复制前一个小时。

该表由三个字段组成 - id (int)、direction_id (int)、created_at (timestamptz)。我需要每小时(基于 created_at 字段)上传数据,其中包含在此“分组”时间之前创建的记录数。但我不仅需要数字,还需要每个direction_id(只有两个-12)。如果在某个时间没有为某个direction_id 创建记录,则复制前一个记录,但结果应以最后一个created_at 结束。 created_at 是创建记录的时间。

【问题讨论】:

  • 那么列数一定是动态的?数据中是否可以有 1 和 2 以外的值?

标签: sql postgresql


【解决方案1】:

在我看来,最好根据一个小时生成一个介于最小和最大日期之间的日期,然后计算每个方向的计数。

Demo

with time_range as (
  select 
    min(created_at) + interval '1 hour' as min, 
    max(created_at) + interval '1 hour' as max
  from test
)
select
  count(*) filter (where direction_id = 1) as "1",
  count(*) filter (where direction_id = 2) as "2",
  to_char(gs.hour, 'dd.mm.yy HH24') as created_at_by_hour
from 
  test t
  cross join time_range tr
  inner join generate_series(tr.min, tr.max, interval  '1 hour') gs(hour)
    on t.created_at <= gs.hour
group by gs.hour
order by gs.hour

【讨论】:

    【解决方案2】:

    将日期截断为小时,按小时分组并计数。然后使用SUM OVER 获得计数的运行总数。为了在表格中显示缺失的小时数,您必须生成一系列小时数并外部连接您的数据。

    with hourly as
    (
      select date_trunc('hour', created_at) as hour, direction_id from mytable
    )
    , hours(hour) as
    (
      select *
      from generate_series
      (
        (select min(hour) from hourly), (select max(hour) from hourly), interval '1 hour'
      )
    )
    select
      hours.hour,
      sum(count(*) filter (where hourly.direction_id = 1)) over (order by hour) as "1",
      sum(count(*) filter (where hourly.direction_id = 2)) over (order by hour) as "2"
    from hours
    left join hourly using (hour)
    group by hour
    order by hour;
    

    演示:https://dbfiddle.uk/?rdbms=postgres_14&fiddle=21d0c838452a09feac4ebc57906829f4

    【讨论】:

      猜你喜欢
      • 2021-06-10
      • 1970-01-01
      • 2017-06-28
      • 2019-08-20
      • 2015-06-01
      • 1970-01-01
      • 2012-07-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多