SQL:返回' 0'如果它不存在,则为一行

时间:2016-06-29 20:10:27

标签: sql oracle

我有一个显示countdatetime的SQL查询。

这是输出的样子:

enter image description here

这是我的SQL查询:

select 
    count(*), 
    to_char(timestamp, 'MM/DD/YYYY'), 
    to_char(timestamp, 'HH24')
from 
    MY_TABLE
where 
    timestamp >= to_timestamp('03/01/2016','MM/DD/YYYY')
group by 
    to_char(timestamp, 'MM/DD/YYYY'), to_char(timestamp, 'HH24') 

现在,在COUNT列中,如果该小时内的计数不存在,我想显示0。因此,3/2/2016位于8amcount6。然后在9am时,计数为0,因此该行未显示。我想显示那一行。在10am& 11am,显示计数然后直到第二天。

那么如何显示count的{​​{1}}?我想每小时显示{strong>每天 0次数 无论是0还是6或其他什么都不重要。谢谢:))

4 个答案:

答案 0 :(得分:2)

使用分区外连接:

SELECT m.day,
       h.hr,
       COALESCE( freq, 0 ) AS freq
FROM   ( SELECT LEVEL - 1 AS hr
         FROM   DUAL
         CONNECT BY LEVEL <= 24
       ) h
       LEFT OUTER JOIN
       ( SELECT COUNT(*) AS freq,
                TO_CHAR( "timestamp", 'mm/dd/yyyy' ) AS day,
                EXTRACT( HOUR FROM "timestamp" ) AS hr
         FROM   MY_TABLE 
         WHERE  "timestamp" >= TIMESTAMP '2016-03-01 00:00:00'
         GROUP BY
                TO_CHAR( "timestamp", 'mm/dd/yyyy' ),
                EXTRACT( HOUR FROM "timestamp" )
       ) m
       PARTITION BY ( m.day, m.hr )
       ON ( m.hr = h.hr );

答案 1 :(得分:1)

使用cte生成一天中所有小时的数字。然后将结果与表中的所有可能日期交叉连接。然后在具有所有日期和小时组合的cte上left join,以便在特定小时缺少行时获得0计数。

with nums(n) as (select 1 from dual
                 union all 
                 select n+1 from nums where n < 24)
,dateshrscomb as (select n,dt 
                   from nums 
                   cross join (select distinct trunc(timestamp) dt from my_table 
                               where timestamp >= to_timestamp('03/01/2016','MM/DD/YYYY')
                               ) alldates
                   )
select count(trunc(m.timestamp)), d.dt, d.n
from dateshrscomb d
left join MY_TABLE m on to_char(m.timestamp, 'HH24') = d.n  
and trunc(m.timestamp) = d.dt
and m.timestamp >= to_timestamp('03/01/2016','MM/DD/YYYY')
group by d.dt, d.n

答案 2 :(得分:1)

with cteHours(h) as (select 0 from dual
                 union all 
                 select h+1 from cteHours where h < 24)

, cteDates(d) AS (
    SELECT
       trunc(MIN(timestamp)) as d
    FROM
       My_Table
    WHERE
       timestamp >= to_timestamp('03/01/2016','MM/DD/YYYY')

    UNION ALL

    SELECT
       d + 1 as d
    FROM
       cteDates
    WHERE
       d + 1 <= (SELECT trunc(MAX(timestamp)) FROM MY_TABLE)
)

, datesNumsCross (d,h) AS (
       SELECT
          d, h
       FROM
          cteDates 
          CROSS JOIN cteHours
)

select count(*), to_char(d.d, 'MM/DD/YYYY'), d.h
from datesNumsCross d
LEFT JOIN MY_TABLE m
ON d.d = trunc(m.timestamp)
AND d.h = to_char(m.timestamp, 'HH24')
group by d.d, d.h

@VPK在回答方面做得很好,我恰好在他上一次编辑的同时编写了这个来生成日期时间交叉连接。这个解决方案与他的不同之处在于它将获得所需的最大值和最小值之间的所有日期。因为他将只获得表格中的日期,所以如果你有一天完全失踪,那么它将不在他的中,而是在这一个中。另外,我对连接做了一些清理。

答案 3 :(得分:1)

这是一种方法。

使用Oracle的分层查询功能和级别的psuedo列,生成日期和小时。 然后对您的数据执行上面的外连接。 需要根据您所需的范围调整级别的值(此示例使用120)。还需要设置开始日期。在这个例子中是(trunc(sysdate,'hh24') - 2/24)。

select nvl(c1.cnt, 0), d1.date_part, d1.hour_part
from
(
    select
      to_char(s.dt - (c.lev)/24, 'mm/dd/yyyy') date_part, 
      to_char(s.dt - (c.lev)/24, 'hh24') hour_part
    from
      (select level lev from dual connect by level <= 120) c,
      (select trunc(sysdate, 'hh24')-2/24 dt from dual) s
    where (s.dt - (c.lev)/24) < trunc(sysdate, 'hh24')-2/24
) d1
full outer join
(
    select 
        count(*) cnt, 
        to_char(timestamp, 'MM/DD/YYYY') date_part, 
        to_char(timestamp, 'HH24') hour_part
    from 
        MY_TABLE
    where 
        timestamp >= to_timestamp('03/01/2016','MM/DD/YYYY')
    group by 
        to_char(timestamp, 'MM/DD/YYYY'), to_char(timestamp, 'HH24') 
) c1
on d1.date_part = c1.date_part
and d1.hour_part = c1.hour_part