Search code examples
sqlpivotprocedure

Dynamic SQL Procedure with Pivot displaying counts based on Date Range


Table

I have a table which contains multiple user entries. I want to pull counts of user entries based on date range passed to a stored procedure.

start date: 11/9/2017 end date: 11/11/2017

However the response needs to be dynamic based on amount of days in the date range.

Here is a desired format: Photo of Format


Solution

  • Now that you have provided examples, I have updated my answer which provides you with a solution based on the data you have provided.

    Note that you are able to change the date range and the query will update accordingly.

    Bare in mind that this SQL query is for SQL Server:

    create table #tbl1 (
        [UserId] int
        ,[UserName] nvarchar(max)
        ,[EntryDateTime] datetime
    );
    
    insert into #tbl1 ([UserId],[UserName],[EntryDateTime])
    values
        (1,'John Doe','20171109')
        ,(1,'John Doe','20171109')
        ,(1,'John Doe','20171110')
        ,(1,'John Doe','20171111')
        ,(2,'Mike Smith','20171109')
        ,(2,'Mike Smith','20171110')
        ,(2,'Mike Smith','20171110')
        ,(2,'Mike Smith','20171110')
    ;
    
    -- declare variables
    declare
        @p1 date
        ,@p2 date
        ,@diff int
        ,@counter1 int
        ,@counter2 int
        ,@dynamicSQL nvarchar(max)
    ;
    
    -- set variables
    set @p1 = '20171109';   -- ENTER THE START DATE IN THE FORMAT YYYYMMDD
    set @p2 = '20171111';   -- ENTER THE END DATE IN THE FORMAT YYYYMMDD
    set @diff = datediff(dd,@p1,@p2); -- used to calculate the difference in days
    set @counter1 = 0;  -- first counter to be used in while loop
    set @counter2 = 0;  -- second counter to be used in while loop
    set @dynamicSQL = 'select pivotTable.[UserId] ,pivotTable.[UserName] as [Name] '; -- start of the dynamic SQL statement
    
    -- to get the dates into the query in a dynamic way, you need to do a while loop (or use a cursor)
    while (@counter1 < @diff)
    begin
        set @dynamicSQL += ',pivotTable.[' + convert(nvarchar(10),dateadd(dd,@counter1,@p1),120) + '] '
    
        set @counter1 = (@counter1 +1)
    end
    
    -- continuation of the dynamic SQL statement
    set @dynamicSQL += ' from (
        select
            t.[UserId]
            ,t.[UserName]
            ,cast(t.[EntryDateTime] as date) as [EntryDate]
            ,count(t.[UserId]) as [UserCount]
        from #tbl1 as t
        where
            t.[EntryDateTime] >= ''' + convert(nvarchar(10),@p1,120) + ''' ' +
            ' and t.[EntryDateTime] <= ''' + convert(nvarchar(10),@p2,120) + ''' ' +
        'group by
            t.[UserId]
            ,t.[UserName]
            ,t.[EntryDateTime]
        ) as mainQuery
    
        pivot (
            sum(mainQuery.[UserCount]) for mainQuery.[EntryDate]
                in ('
    ;
    
    -- the second while loop which is used to create the columns in the pivot table
    while (@counter2 < @diff)
    begin
        set @dynamicSQL += ',[' + convert(nvarchar(10),dateadd(dd,@counter2,@p1),120) + ']'
    
        set @counter2 = (@counter2 +1)
    end
    
    -- continuation of the SQL statement
    set @dynamicSQL += ')
        ) as pivotTable'
    ;
    
    -- this is the easiet way I could think of to get rid of the leading comma in the query
    set @dynamicSQL = replace(@dynamicSQL,'in (,','in (');
    
    print @dynamicSQL   -- included this so that you can see the SQL statement that is generated
    
    exec sp_executesql @dynamicSQL; -- this will run the generate dynamic SQL statement
    
    drop table #tbl1;
    

    Let me know if that's what you were looking for.