2012-11-14 33 views
5

Có cách nào dễ dàng để thực hiện việc này không? Bởi hoàn toàn giữa, tôi có nghĩa là không tính số liệu 7am hoặc 7 giờ chiều bằng với thời gian bắt đầu hoặc kết thúc.Đếm số lần xuất hiện 7AM hoặc 7PM giữa hai chế độ xem

Tôi tưởng tượng điều này có thể được thực hiện bằng cách sử dụng dấu thời gian unix trong vài giây và một chút đại số, nhưng tôi không thể tìm ra.

Tôi rất vui khi sử dụng điều gì đó trong SQL PLSQL hoặc SQL thuần túy.

Ví dụ:

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 

Trả lời

3

Tôi nghĩ rằng điều này có thể giảm hơn nữa nhưng tôi không có Oracle sắp xếp của tôi để hoàn toàn kiểm tra Oracle SQL này:

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; 

Nhờ @ABCade cho Fiddle, nó trông giống như logic trường hợp của tôi có thể được ngưng tụ hơn nữa để:

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; 
+1

Có vẻ như bạn đang đi đúng hướng - bạn có thể sử dụng câu lệnh này http://www.sqlfiddle.com/#!4/baead/2 –

+0

Cảm ơn Fiddle. Nhìn nó đi. –

+0

chưa được chấp nhận. [http://www.sqlfiddle.com/#!4/baead/6](http://www.sqlfiddle.com/#!4/baead/6). Đầu tiên, sẽ đếm 1 khi cả hai giờ sẽ nhỏ hơn 7 (nên bằng 0) hoặc cả hai đều lớn hơn 19. Thứ hai, không tính đến phút. Ví dụ, không tính số 19:01. –

2

này có thể không có hiệu suất tốt nhất nhưng có thể làm việc cho bạn:

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 

UPDATE: Đối với @ bình luận FlorinGhita của - cố định các truy vấn để bao gồm zero lần xuất hiện

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 
+0

sẽ loại trừ hàng với zero lần xuất hiện –

+0

@FlorinGhita, cảm ơn, cố định truy vấn của tôi –

+0

1 Tôi nghĩ rằng đó là ok ngay bây giờ. –

1

làm như thế này (trong 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 
3

tôi đã vui vẻ bằng văn bản cho giải pháp sau đây:

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; 

Tôi đã thêm cột id vào bảng trong trường hợp phạm vi ngày không phải là duy nhất.

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

Các vấn đề liên quan