SQL查询,将数据按小时按列分组,日期按行分组

SQL查询,将数据按小时按列分组,日期按行分组,sql,oracle,pivot,Sql,Oracle,Pivot,我使用Oracle并具有下表: create table test as select to_date('25.12.2017 00:01', 'DD.MM.YYYY HH24:MI') as DT, 203.4 as VAL from dual union all select to_date('25.12.2017 00:15', 'DD.MM.YYYY HH24:MI') as DT, 206.7 as VAL from dual union all select to_date('25.

我使用Oracle并具有下表:

create table test as
select to_date('25.12.2017 00:01', 'DD.MM.YYYY HH24:MI') as DT, 203.4 as VAL from dual union all
select to_date('25.12.2017 00:15', 'DD.MM.YYYY HH24:MI') as DT, 206.7 as VAL from dual union all
select to_date('25.12.2017 01:30', 'DD.MM.YYYY HH24:MI') as DT, 208.9 as VAL from dual union all
select to_date('25.12.2017 12:30', 'DD.MM.YYYY HH24:MI') as DT, 211.8 as VAL from dual union all
select to_date('26.12.2017 01:00', 'DD.MM.YYYY HH24:MI') as DT, 212.3 as VAL from dual union all
select to_date('26.12.2017 06:15', 'DD.MM.YYYY HH24:MI') as DT, 214.5 as VAL from dual union all
select to_date('26.12.2017 08:12', 'DD.MM.YYYY HH24:MI') as DT, 215 as VAL from dual
;


DT                   VAL
----------------------------
25.12.2017 00:01     203.4
25.12.2017 00:15     206.7
25.12.2017 01:30     208.9
25.12.2017 12:30     211.8
26.12.2017 01:00     212.3
26.12.2017 06:15     214.5
26.12.2017 08:12     215 
我需要以表格的形式呈现这些数据,以小时为列,日期为行。数据必须在小时内汇总,即“1:00”列应包含时间戳介于00:01和01:00之间的数据汇总。此外,“总计”列应包含一行中所有数据的总和

要求的样本输出如下所示:

是否可以通过一个查询解决此任务?

您可以从11g中透视内置语法;早期版本中的手动等效简单。如何组织存储桶的问题在于,您必须稍微调整值:

select *
from (
  select trunc(dt - 1/86400) as dt,
    sum(val) over (partition by trunc(dt - 1/86400)) as total,
    to_char(trunc(dt - 1/86400, 'HH') + 1/24, 'HH24') as hr,
    val
  from test
)
pivot (sum(val) for hr in ('01' as "1:00", '02' as "2:00", '03' as "3:00",
  '04' as "4:00")) -- all 24 pairs
order by dt;

DT              TOTAL       1:00       2:00       3:00       4:00
---------- ---------- ---------- ---------- ---------- ----------
2017-12-25      830.8      410.1      208.9                      
2017-12-26      641.8      212.3                                 
dt-1/86400将精确的01:00:00时间向后移动一秒钟,因此它位于00:00:00到00:59:59窗口中;然后对于显示,窗口中的所有内容都向前移动了一个小时,因此显示为01:00。您只提到“1:00”列中出现的00:01和01:00之间的时间;但我假设您希望在同一个桶中包含00:00:01和00:00:59之间的任何数据;如果没有,则调整一分钟,而不是一秒钟。那会更奇怪,尽管

在in条款中为其他时间添加更多条款;如果您想要零而不是null,只需在选择列表中的每个生成列周围添加nvl或合并,而不是使用*

您可以从11g透视内置语法;早期版本中的手动等效简单。如何组织存储桶的问题在于,您必须稍微调整值:

select *
from (
  select trunc(dt - 1/86400) as dt,
    sum(val) over (partition by trunc(dt - 1/86400)) as total,
    to_char(trunc(dt - 1/86400, 'HH') + 1/24, 'HH24') as hr,
    val
  from test
)
pivot (sum(val) for hr in ('01' as "1:00", '02' as "2:00", '03' as "3:00",
  '04' as "4:00")) -- all 24 pairs
order by dt;

DT              TOTAL       1:00       2:00       3:00       4:00
---------- ---------- ---------- ---------- ---------- ----------
2017-12-25      830.8      410.1      208.9                      
2017-12-26      641.8      212.3                                 
dt-1/86400将精确的01:00:00时间向后移动一秒钟,因此它位于00:00:00到00:59:59窗口中;然后对于显示,窗口中的所有内容都向前移动了一个小时,因此显示为01:00。您只提到“1:00”列中出现的00:01和01:00之间的时间;但我假设您希望在同一个桶中包含00:00:01和00:00:59之间的任何数据;如果没有,则调整一分钟,而不是一秒钟。那会更奇怪,尽管

在in条款中为其他时间添加更多条款;如果您想要零而不是null,只需在选择列表中的每个生成列周围添加nvl或合并,而不是使用*


这将是一个PIVOT查询

由于您的表不包含一天中的所有小时,因此WITH factoring子句创建的小时将创建一天中的所有小时。它与您的表进行外部连接,计算值,最后,枢轴按您的需要进行排列。GROUP BY ROLLUP创建总值

with hours as 
  (select trunc(sysdate) + level/24 hr from dual 
   connect by level <= 24),
podaci as 
  (select to_char(t.dt, 'dd.mm.yyyy') dt, 
       nvl(to_char(h.hr, 'hh24'), 'TOTAL') hr, 
       sum(t.val) sum_val
   from hours h
   left join test t on to_char(trunc(h.hr - 1/(24*60), 'hh24'), 'hh24') = 
                       to_char(trunc(t.dt - 1/(24*60), 'hh24'), 'hh24')
   group by rollup(to_char(t.dt, 'dd.mm.yyyy'), to_char(h.hr, 'hh24'))
  )
select *
from podaci 
pivot (max(sum_val)
       for hr in ('01', '02', '03', '04', '05', '06',
                  '07', '08', '09', '10', '11', '12', 
                  '13', '14', '15', '16', '17', '18',
                  '19', '20', '21', '22', '23', '00',
                  'TOTAL'))
where dt is not null
order by 1, 2;       

这将是一个PIVOT查询

由于您的表不包含一天中的所有小时,因此WITH factoring子句创建的小时将创建一天中的所有小时。它与您的表进行外部连接,计算值,最后,枢轴按您的需要进行排列。GROUP BY ROLLUP创建总值

with hours as 
  (select trunc(sysdate) + level/24 hr from dual 
   connect by level <= 24),
podaci as 
  (select to_char(t.dt, 'dd.mm.yyyy') dt, 
       nvl(to_char(h.hr, 'hh24'), 'TOTAL') hr, 
       sum(t.val) sum_val
   from hours h
   left join test t on to_char(trunc(h.hr - 1/(24*60), 'hh24'), 'hh24') = 
                       to_char(trunc(t.dt - 1/(24*60), 'hh24'), 'hh24')
   group by rollup(to_char(t.dt, 'dd.mm.yyyy'), to_char(h.hr, 'hh24'))
  )
select *
from podaci 
pivot (max(sum_val)
       for hr in ('01', '02', '03', '04', '05', '06',
                  '07', '08', '09', '10', '11', '12', 
                  '13', '14', '15', '16', '17', '18',
                  '19', '20', '21', '22', '23', '00',
                  'TOTAL'))
where dt is not null
order by 1, 2;       
这适用于我的SQL

SELECT DISTINCT CONCAT(EXTRACT(DAY FROM DT), "-", EXTRACT(MONTH FROM DT), "-", EXTRACT(YEAR FROM DT)) AS DATE
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 0 THEN VAL END) AS '0'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 1 THEN VAL END) AS '1'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 2 THEN VAL END) AS '2'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 3 THEN VAL END) AS '3'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 4 THEN VAL END) AS '4'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 5 THEN VAL END) AS '5'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 6 THEN VAL END) AS '6'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 7 THEN VAL END) AS '7'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 8 THEN VAL END) AS '8'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 9 THEN VAL END) AS '9'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 10 THEN VAL END) AS '10'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 11 THEN VAL END) AS '11'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 12 THEN VAL END) AS '12'
 FROM test
 GROUP BY CONCAT(EXTRACT(DAY FROM DT), "-", EXTRACT(MONTH FROM DT), "-", EXTRACT(YEAR FROM DT));
这适用于我的SQL

SELECT DISTINCT CONCAT(EXTRACT(DAY FROM DT), "-", EXTRACT(MONTH FROM DT), "-", EXTRACT(YEAR FROM DT)) AS DATE
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 0 THEN VAL END) AS '0'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 1 THEN VAL END) AS '1'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 2 THEN VAL END) AS '2'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 3 THEN VAL END) AS '3'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 4 THEN VAL END) AS '4'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 5 THEN VAL END) AS '5'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 6 THEN VAL END) AS '6'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 7 THEN VAL END) AS '7'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 8 THEN VAL END) AS '8'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 9 THEN VAL END) AS '9'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 10 THEN VAL END) AS '10'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 11 THEN VAL END) AS '11'
, SUM(CASE WHEN EXTRACT(HOUR FROM DT) = 12 THEN VAL END) AS '12'
 FROM test
 GROUP BY CONCAT(EXTRACT(DAY FROM DT), "-", EXTRACT(MONTH FROM DT), "-", EXTRACT(YEAR FROM DT));