2012-11-14 2 views
5

Gibt es eine einfache Möglichkeit, dies zu tun? Mit ganz zwischen, ich meine nicht zählen die 7 Uhr oder 7 Uhr Datumsangaben, die gleich der Start- oder Endzeit sind.Zählen Sie die Anzahl von 7 AM oder 7 PM Vorkommen zwischen zwei Datum

Ich kann mir vorstellen, dass dies mit dem Unix-Timestamp in Sekunden und ein bisschen Algebra gemacht werden kann, aber ich kann es nicht herausfinden.

Ich bin glücklich, etwas in PLSQL oder plain SQL zu verwenden.

Beispiele:

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 

Antwort

3

Ich denke, das weiter reduziert werden könnte, aber ich habe nicht Oracle zu meiner Verfügung vollständig dieses Oracle SQL testen:

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; 

Vielen Dank für die Fiddle @ABCade, es ist wie meine CASE sieht Logic kondensiert werden weiter:

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

Sieht aus, als ob du in der richtigen Weise bist - du kannst diese Geige benutzen http://www.sqlfiddle.com/#!4/baead/2 –

+0

Danke für die Fiddle. Schau es dir jetzt an. –

+0

ist noch nicht ok. [http://www.sqlfiddle.com/#!4/baead/6](http://www.sqlfiddle.com/#!4/baead/6). Zuerst wird 1 gezählt, wenn beide Stunden kleiner als 7 sind (sollte Null sein) oder beide sind größer als 19. Zweitens, berücksichtigt keine Minuten. Zum Beispiel zählt das 19:01 nicht. –

2

Dies ist nicht die beste Leistung haben, aber könnte für Sie arbeiten:

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: Was @ FlorinGhita Kommentar - fixiert die Abfrage Null einschließen Vorkommen

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

wird ausschließen Zeilen mit Null Vorkommnissen –

+0

@FlorinGhita, danke, festen meine Anfrage –

+0

+1 Ich denke, es ist jetzt in Ordnung ist. –

1

tun, wie folgt (in 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

ich hatte Spaß die folgende Lösung zu schreiben:

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; 

Ich habe eine ID-Spalte zur Tabelle hinzugefügt, falls der Datumsbereich nicht eindeutig ist.

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

Verwandte Themen