5

是否有捷径可寻?完全介于两者之间,我的意思是不要计算等于开始时间或结束时间的上午 7 点或晚上 7 点的日期时间。

我想这可以在几秒钟内使用 unix 时间戳和一些代数来完成,但我无法弄清楚。

我很高兴在 PLSQL 或普通 SQL 中使用某些东西。

例子:

start             end               num_7am_7pm_between_dates
2012-06-16 05:00  2012-06-16 08:00  1  
2012-06-16 16:00  2012-06-16 20:00  1
2012-06-16 05:00  2012-06-16 07:00  0
2012-06-16 07:00  2012-06-16 19:00  0
2012-06-16 08:00  2012-06-16 15:00  0
2012-06-16 05:00  2012-06-16 19:01  2
2012-06-16 05:00  2012-06-18 20:00  6 
4

4 回答 4

3

我认为这可以进一步减少,但我没有 Oracle 可以完全测试这个 Oracle SQL:

SELECT StartDate
     , EndDate
     , CASE WHEN TRUNC(EndDate) - TRUNC(StartDate) < 1
             AND TO_CHAR(EndDate, 'HH24') > 19
             AND TO_CHAR(StartDate, 'HH24') < 7
            THEN 2
            WHEN TRUNC(EndDate) - TRUNC(StartDate) < 1
             AND (TO_CHAR(EndDate, 'HH24') > 19
              OR  TO_CHAR(StartDate, 'HH24') < 7)
            THEN 1
            WHEN TRUNC(EndDate) - TRUNC(StartDate) > 0
             AND TO_CHAR(EndDate, 'HH24') > 19
             AND TO_CHAR(StartDate, 'HH24') < 7
            THEN 2 + ((TRUNC(EndDate) - TRUNC(StartDate)) * 2)
            WHEN TRUNC(EndDate) - TRUNC(StartDate) > 0
             AND TO_CHAR(EndDate, 'HH24') > 19
              OR TO_CHAR(StartDate, 'HH24') < 7
            THEN 1 + ((TRUNC(EndDate) - TRUNC(StartDate)) * 2)
            ELSE 0
       END
FROM MyTable;

感谢@ABCade for the Fiddle,看起来我的 CASE Logic 可以进一步压缩为:

SELECT SDate
     , EDate
     , CASE WHEN TO_CHAR(EDate, 'HH24') > 19
             AND TO_CHAR(SDate, 'HH24') < 7
            THEN 2 + ((TRUNC(EDate) - TRUNC(SDate)) * 2)
            WHEN TO_CHAR(EDate, 'HH24') > 19
              OR TO_CHAR(SDate, 'HH24') < 7
            THEN 1 + ((TRUNC(EDate) - TRUNC(SDate)) * 2)
            ELSE 0
       END AS MyCalc2
  FROM MyTable;
于 2012-11-14T07:11:34.173 回答
3

我在编写以下解决方案时玩得很开心:

with date_range as (
  select min(sdate) as sdate, max(edate) as edate
  from t
),
all_dates as (
  select sdate + (level-1)/24 as hour
  from date_range
  connect by level <= (edate-sdate) * 24 + 1
),
counts as (
  select t.id, count(*) as c
  from all_dates, t
  where to_char(hour, 'HH') = '07'
  and hour > t.sdate and hour < t.edate
  group by t.id
)
select t.sdate, t.edate, nvl(counts.c, 0)
from t, counts
where t.id = counts.id(+)
order by t.id;

我在表中添加了一个 id 列,以防日期范围不是唯一的。

http://www.sqlfiddle.com/#!4/5fa19/13

于 2012-11-14T10:33:34.530 回答
2

这可能没有最佳性能,但可能对您有用:

select sdate, edate, count(*)
  from (select distinct edate, sdate, sdate + (level / 24) hr
          from t
        connect by sdate + (level / 24) <= edate )
 where to_char(hr, 'hh') = '07'
group by sdate, edate

更新:关于@FlorinGhita 的评论 - 修复了查询以包含零出现

select sdate, edate, sum( decode(to_char(hr, 'hh'), '07',1,0))
  from (select distinct edate, sdate, sdate + (level / 24) hr
          from t
        connect by sdate + (level / 24) <= edate )
group by sdate, edate
于 2012-11-14T07:10:00.320 回答
1

这样做(在 SQL 中)

declare  @table table ( start datetime, ends datetime) 
insert into @table select'2012-06-16 05:00','2012-06-16 08:00'  --1  
insert into @table select'2012-06-16 16:00','2012-06-16 20:00'  --1
insert into @table select'2012-06-16 05:00','2012-06-16 07:00'  --0
insert into @table select'2012-06-16 07:00','2012-06-16 19:00'  --0
insert into @table select'2012-06-16 08:00','2012-06-16 15:00'  --0
insert into @table select'2012-06-16 05:00','2012-06-16 19:01'  --2
insert into @table select'2012-06-16 05:00','2012-06-18 20:00'  --6 
insert into @table select'2012-06-16 07:00','2012-06-18 07:00'  --3


Declare @From DATETIME 
Declare @To DATETIME 

select @From = MIN(start) from @table 
select @To = max(ends) from @table 

;with CTE AS 
( 
      SELECT distinct 
    DATEADD(DD,DATEDIFF(D,0,start),0)+'07:00' AS AimTime
    FROM @table 
 ),CTE1 AS 
 ( 
    Select AimTime
    FROM CTE 

    UNION ALL 

    Select DATEADD(hour, 12, AimTime)
From CTE1 
WHERE AimTime< @To 
 )


 select start,ends, count(AimTime)
 from CTE1 right join @table t 
 on t.start < CTE1.AimTime and t.ends > CTE1.AimTime
 group by start,ends 
于 2012-11-14T09:31:46.020 回答