统计一个时间跨度内每小时的记录数

Count records per hour within a time span

我有一个 table,其中包含用户 ID、开始日期和结束日期。 我想按小时统计关注的userID数量

例如startDate = '21/05/2014 01:15:00' 且endDate = '21/05/2014 05:22:00' 的用户 '4242' 应该从01开始算一次到 02,一次从 02 到 03,一次从 03 到 04,...

它会给出这样的结果:

DATE AND TIME                   COUNT
-------------------------------------
20140930 18-19                    198 
20140930 19-20                    220 
20140930 20-21                    236 
20140930 21-22                    257 
20140930 22-23                    257 
20140930 23-00                    257 
20141001 00-01                    259 
20141001 01-02                    259 
20141001 02-03                    258 
20141001 03-04                    259 
20141001 04-05                    258 
20141001 05-06                    258 

你会怎么做?

好吧,我尝试了很多东西。这是我最近的尝试。如果代码太乱,请不要阅读它,请告诉我您将如何处理这个问题;)谢谢!

WITH timespan AS (
   SELECT lpad(rownum - 1,2,'00') ||'-'|| lpad(mod(rownum,24),2,'00') AS hours
    FROM dual
   connect BY level <= 24
  ),

 UserID_min_max AS (
   SELECT  USERS.UserID, 
          min(USERS.date_startUT) AS min_date,
          max(USERS.date_end) AS max_date,
          code_etat
   FROM      USERS

 WHERE    (
    (USERS.date_startUT  >=  to_date('01/10/2014 00:00:00','dd/MM/YYYY HH24:mi:ss')
    AND  USERS.date_end  <=  to_date('08/10/2014 23:59:00','dd/MM/YYYY HH24:mi:ss'))
    OR  ( USERS.date_startUT  <=  to_date('01/10/2014 00:00:00','dd/MM/YYYY HH24:mi:ss')
    AND  USERS.date_end  >=  to_date('01/10/2014 00:00:00','dd/MM/YYYY HH24:mi:ss')
    AND   USERS.date_end  <=  to_date('08/10/2014 23:59:00','dd/MM/YYYY HH24:mi:ss'))
    OR   (USERS.date_startUT  BETWEEN  to_date('01/10/2014 00:00:00','dd/MM/YYYY HH24:mi:ss') AND to_date('08/10/2014 23:59:00','dd/MM/YYYY HH24:mi:ss')))
  GROUP BY USERS.UserID, code_etat
  ),

  hours_list AS (
   SELECT  UserID, min_date, max_date, code_etat
    , to_char(min_date + row_number() over (partition BY UserID ORDER BY 1)-1,'yyyymmdd') AS days
    , to_char(min_date,'yyyymmdd') AS date_start
    , to_char(min_date, 'hh24') || '-' || lpad(to_number(to_char(min_date, 'hh24')) + 1, 2, '00') AS timespan_date_start
    , to_char(max_date,'yyyymmdd') AS date_end
    , to_char(max_date, 'hh24') || '-' || lpad(to_number(to_char(max_date, 'hh24')) + 1, 2, '00') AS timespan_date_end

  FROM UserID_min_max cmm
   connect BY level <= trunc(max_date) - trunc(min_date)+1
    AND PRIOR UserID = UserID
    AND prior sys_guid() IS NOT NULL
  ),

  all_timespan_hours_list AS (
   SELECT lj.*, t.*, lj.days ||' '|| t.hours AS days_hours
   FROM hours_list lj
   JOIN timespan t
   ON lj.days || t.hours >= lj.date_start || lj.timespan_date_start
   AND lj.days || t.hours <= lj.date_end || lj.timespan_date_end
  )

SELECT DISTINCT days_hours, COUNT(*)
FROM (

   SELECT *

   FROM all_timespan_hours_list ttlj

    WHERE CODE_ETAT IN ('SOH','SOL')

  )
  GROUP BY days_hours
  ORDER BY days_hours;

试试这个:

SELECT
  DATE_FORMAT(your_datetime_column, '%Y%m%d %H') AS `hourly`,
  COUNT(*) AS `count`
FROM your_table
GROUP BY DATE_FORMAT(your_datetime_column, '%Y%m%d %H')

下面是我将如何做类似的事情:

with dt_tab as (select trunc(:p_start_date, 'hh') + (level - 1)/24 hr
                from   dual
                connect by level <= (trunc(:p_end_date, 'hh') - trunc(:p_start_date, 'hh'))*24 + 1),
sample_data as (select 4242 usr, to_date('21/05/2015 01:15:00', 'dd/mm/yyyy hh24:mi:ss') start_date, to_date('21/05/2015 05:22:00', 'dd/mm/yyyy hh24:mi:ss') end_date from dual union all
                select 4243 usr, to_date('20/05/2015 18:32:42', 'dd/mm/yyyy hh24:mi:ss') start_date, to_date('21/05/2015 01:36:56', 'dd/mm/yyyy hh24:mi:ss') end_date from dual union all
                select 4244 usr, to_date('21/05/2015 07:00:00', 'dd/mm/yyyy hh24:mi:ss') start_date, null end_date from dual)
select   to_char(dt.hr, 'dd/mm/yyyy hh24-')||to_char(dt.hr + 1/24, 'hh24') date_and_time,
         count(sd.usr) cnt
from     dt_tab dt
         left outer join sample_data sd on (dt.hr < nvl(sd.end_date, :p_end_date) and dt.hr >= sd.start_date)
group by to_char(dt.hr, 'dd/mm/yyyy hh24-')||to_char(dt.hr + 1/24, 'hh24')
order by date_and_time;

:p_start_date := 20/05/2015 08:00:00
:p_end_date := 21/05/2015 08:00:00

DATE_AND_TIME    CNT
---------------- ---
20/05/2015 08-09   0
20/05/2015 09-10   0
20/05/2015 10-11   0
20/05/2015 11-12   0
20/05/2015 12-13   0
20/05/2015 13-14   0
20/05/2015 14-15   0
20/05/2015 15-16   0
20/05/2015 16-17   0
20/05/2015 17-18   0
20/05/2015 18-19   0
20/05/2015 19-20   1
20/05/2015 20-21   1
20/05/2015 21-22   1
20/05/2015 22-23   1
20/05/2015 23-00   1
21/05/2015 00-01   1
21/05/2015 01-02   1
21/05/2015 02-03   1
21/05/2015 03-04   1
21/05/2015 04-05   1
21/05/2015 05-06   1
21/05/2015 06-07   0
21/05/2015 07-08   1
21/05/2015 08-09   0

(根据您的时间段开始日期和结束日期的配置方式,您可能希望更改使用绑定变量 - 例如,在 table 中使用 min/max 日期等)


当我在 Toad 中 运行 以上内容有效。对于在 SQL*Plus 中工作的东西,或者当你 运行 它作为脚本(例如在 Toad 中)时,下面应该工作:

variable p_start_date varchar2(20)
variable p_end_date varchar2(20)

exec :p_start_date := '20/05/2015 08:00:00';
exec :p_end_date := '21/05/2015 08:00:00';


with dt_tab as (select trunc(to_date(:p_start_date, 'dd/mm/yyyy hh24:mi:ss'), 'hh') + (level - 1)/24 hr
                from   dual
                connect by level <= (trunc(to_date(:p_end_date, 'dd/mm/yyyy hh24:mi:ss'), 'hh') - trunc(to_date(:p_start_date, 'dd/mm/yyyy hh24:mi:ss'), 'hh'))*24 + 1),
sample_data as (select 4242 usr, to_date('21/05/2015 01:15:00', 'dd/mm/yyyy hh24:mi:ss') start_date, to_date('21/05/2015 05:22:00', 'dd/mm/yyyy hh24:mi:ss') end_date from dual union all
                select 4243 usr, to_date('20/05/2015 18:32:42', 'dd/mm/yyyy hh24:mi:ss') start_date, to_date('21/05/2015 01:36:56', 'dd/mm/yyyy hh24:mi:ss') end_date from dual union all
                select 4244 usr, to_date('21/05/2015 07:00:00', 'dd/mm/yyyy hh24:mi:ss') start_date, null end_date from dual)
select   to_char(dt.hr, 'dd/mm/yyyy hh24-')||to_char(dt.hr + 1/24, 'hh24') date_and_time,
         count(sd.usr) cnt
from     dt_tab dt
         left outer join sample_data sd on (dt.hr < nvl(sd.end_date, to_date(:p_end_date, 'dd/mm/yyyy hh24:mi:ss')) and dt.hr >= sd.start_date)
group by to_char(dt.hr, 'dd/mm/yyyy hh24-')||to_char(dt.hr + 1/24, 'hh24')
order by date_and_time;

尝试像这样使用函数 TRUNC(date,[fmt])

select trunc(some_date, 'HH24') 
from some_table
group by trunc(some_date, 'HH24');