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

时间:2018-01-27 08:03:07

标签: 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.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之间的数据总和。此外,“总计”列应包含一行中所有数据的总和。

下面给出了所需的样本输出: Required output

是否可以使用单个查询解决此任务?

3 个答案:

答案 0 :(得分:4)

你可以pivot(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。 (您只在00:01和01:00列中显示00:01和01:00之间的时间;但我假设您在00:00之间需要任何数据: 01和00:00:59在同一个桶中;如果没有则调整一分钟而不是一秒钟。这甚至会更奇怪......)

在其他时间内在in()子句中添加更多字词;如果你想要零而不是null,只需在选择列表中的每个生成列周围添加nvlcoalesce,而不是使用*

select dt, total, nvl("1:00", 0) as "1:00", nvl("2:00", 0) as "2:00",
  nvl("3:00", 0) as "3:00", nvl("4:00", 0) as "4:00" -- all 24 hours
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          0          0
2017-12-26      641.8      212.3          0          0          0

答案 1 :(得分:1)

这将是一个PIVOT查询。

由于您的表格不包含一天中的所有小时数,因此HOURS(由WITH因子子句创建)会创建一天中的所有小时数。它外部连接到你的桌子,计算值,最后,PIVOT根据你的需要安排它。 GROUP BY ROLLUP创建TOTAL值。

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;       

答案 2 :(得分:0)

这适用于My 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));