Insert Dates in the return from a query where there is none

前端 未结 5 1328
慢半拍i
慢半拍i 2020-12-01 22:09

We are building a query to count the number of events per hour, per day. Most days there are hours that do not have any activity and therefore where the query is run the cou

5条回答
  •  无人及你
    2020-12-01 22:19

    First I created a table function based on the recursive common table query described by Dave Markle (thanks for showing me this Dave!). This is extremely sweet because I only have to make the function once and I can use it for analysing any intervals.

    if exists (select * from dbo.sysobjects where name = 'fn_daterange') drop function fn_daterange;
    go
    
    create function fn_daterange
       (
       @MinDate as datetime,
       @MaxDate as datetime,
       @intval  as datetime
       )
    returns table
    --**************************************************************************
    -- Procedure: fn_daterange()
    --    Author: Ron Savage
    --      Date: 12/16/2008
    --
    -- Description:
    -- This function takes a starting and ending date and an interval, then
    -- returns a table of all the dates in that range at the specified interval.
    --
    -- Change History:
    -- Date        Init. Description
    -- 12/16/2008  RS    Created.
    -- **************************************************************************
    as
    return
       WITH times (startdate, enddate, intervl) AS
          (
          SELECT @MinDate as startdate, @MinDate + @intval - .0000001 as enddate, @intval as intervl
             UNION ALL
          SELECT startdate + intervl as startdate, enddate + intervl as enddate, intervl as intervl
          FROM times
          WHERE startdate + intervl <= @MaxDate
          )
       select startdate, enddate from times;
    
    go
    

    So if you do a select from that function all by itself you get a table of time intervals like this:

    fn_daterange('12/14/2008 10:00:00', '12/14/2008 20:00:00', '01:00:00' )

    returns:

    startdate               enddate                 intervl                 
    ----------------------- ----------------------- ----------------------- 
    2008-12-14 10:00:00.000 2008-12-14 10:59:59.997 1900-01-01 01:00:00.000 
    2008-12-14 11:00:00.000 2008-12-14 11:59:59.997 1900-01-01 01:00:00.000 
    2008-12-14 12:00:00.000 2008-12-14 12:59:59.997 1900-01-01 01:00:00.000 
    2008-12-14 13:00:00.000 2008-12-14 13:59:59.997 1900-01-01 01:00:00.000 
    2008-12-14 14:00:00.000 2008-12-14 14:59:59.997 1900-01-01 01:00:00.000 
    2008-12-14 15:00:00.000 2008-12-14 15:59:59.997 1900-01-01 01:00:00.000 
    2008-12-14 16:00:00.000 2008-12-14 16:59:59.997 1900-01-01 01:00:00.000 
    2008-12-14 17:00:00.000 2008-12-14 17:59:59.997 1900-01-01 01:00:00.000 
    2008-12-14 18:00:00.000 2008-12-14 18:59:59.997 1900-01-01 01:00:00.000 
    2008-12-14 19:00:00.000 2008-12-14 19:59:59.997 1900-01-01 01:00:00.000 
    2008-12-14 20:00:00.000 2008-12-14 20:59:59.997 1900-01-01 01:00:00.000 
    

    Then I made a sample table of event data:

        eventdate               eventnote            
        ----------------------- -------------------- 
        2008-12-14 10:01:00.000 oo! an event!        
        2008-12-14 10:01:00.000 oo! an event!        
        2008-12-14 10:01:00.000 oo! an event!        
        2008-12-14 10:01:00.000 oo! an event!        
        2008-12-14 10:23:00.000 oo! an event!        
        2008-12-14 10:23:00.000 oo! an event!        
        2008-12-14 10:23:00.000 oo! an event!        
        2008-12-14 11:23:00.000 oo! an event!        
        2008-12-14 11:23:00.000 oo! an event!        
        2008-12-14 11:23:00.000 oo! an event!        
        2008-12-14 11:23:00.000 oo! an event!        
        2008-12-14 11:23:00.000 oo! an event!        
        2008-12-14 14:23:00.000 oo! an event!        
        2008-12-14 14:23:00.000 oo! an event!        
        2008-12-14 14:23:00.000 oo! an event!        
        2008-12-14 19:23:00.000 oo! an event!        
        2008-12-14 19:23:00.000 oo! an event!        
        2008-12-14 19:23:00.000 oo! an event!        
        2008-12-14 19:23:00.000 oo! an event!        
        2008-12-14 19:00:00.000 oo! an event!        
        2008-12-14 19:00:00.000 oo! an event!        
        2008-12-14 19:00:00.000 oo! an event!        
    
        22 Row(s) affected
    

    Then I hooked them together with a LEFT OUTER JOIN like so:

    select
       dr.startdate,
       dr.enddate,
       count(me.eventdate) as eventcount
    from
       fn_daterange('12/14/2008 10:00:00', '12/14/2008 20:00:00', '01:00:00' ) dr
    
       LEFT OUTER JOIN myevents me
          on ( me.eventdate between dr.startdate and dr.enddate)
    group by
       dr.startdate,
       dr.enddate
    
    
    startdate               enddate                 eventcount 
    ----------------------- ----------------------- ---------- 
    2008-12-14 10:00:00.000 2008-12-14 10:59:59.993 7          
    2008-12-14 11:00:00.000 2008-12-14 11:59:59.993 5          
    2008-12-14 12:00:00.000 2008-12-14 12:59:59.993 0          
    2008-12-14 13:00:00.000 2008-12-14 13:59:59.993 0          
    2008-12-14 14:00:00.000 2008-12-14 14:59:59.993 3          
    2008-12-14 15:00:00.000 2008-12-14 15:59:59.993 0          
    2008-12-14 16:00:00.000 2008-12-14 16:59:59.993 0          
    2008-12-14 17:00:00.000 2008-12-14 17:59:59.993 0          
    2008-12-14 18:00:00.000 2008-12-14 18:59:59.993 0          
    2008-12-14 19:00:00.000 2008-12-14 19:59:59.993 7          
    2008-12-14 20:00:00.000 2008-12-14 20:59:59.993 0          
    
    11 Row(s) affected
    

    HOLY CRAP that is sweet - I can use this for all kinds of analysis at work! :-)

    Thanks Fred for the question and Dave for the info on common table queries!

    Ron

提交回复
热议问题