Search code examples
sql-server-2008reporting-servicesgroup-byssrs-2008presentation

SSRS 2008R2 - Fixed Row/Column Groups


I've been using SQL hacks to force empty groups and the like but I'm tired of doing it, I want a presentation layer solution for a presentation layer problem. I'm using SQL/SSRS 2008 R2 and I'm encountering more and more situations like the situation below.

I've got column groups for dates and I've got a row group for job state (cancelled or not) and status. My problem comes in when I have a day with no jobs or a month without a cancellation of a certain type. My requirements state that the report layout must be fixed and these rows/columns must still exist but just state 0. To make matters worse, the number of distinct statuses for one job state (cancelled) is dynamic in itself and pulled from a table, although, the number of statuses for the other job state (not cancelled) is fixed.

My question is, can I form this report layout:

https://i.sstatic.net/0UNZU.jpg

From these datasets?:

https://i.sstatic.net/zsqNw.jpg

-within SSRS or am I stuck with just having to continue SQL trickery to force that layout?


Solution

  • I know the question is quite old by now, if not you, I hope this answer can help somebody else.

    Based in what you wrote, what you need are Common Table Expressions and a pivot table with dynamic columns.

    Here is the code:

    --
    -- We create the needed schemas and fill them with your data.
    --    
    
    CREATE TABLE Jobs(Date DATE, State NVARCHAR(32), Status NVARCHAR(32));
    CREATE TABLE CancellationTypes (State NVARCHAR(32), Reasons NVARCHAR(32));
    
    --
    -- Added the Status column so we can get the cancellation types before
    -- the jobs. This way we can get the zeros you need.
    --
    
    INSERT INTO CancellationTypes VALUES('Cancelled', 'Weather');
    INSERT INTO CancellationTypes VALUES('Cancelled', 'Equipment Failure');
    INSERT INTO CancellationTypes VALUES('Cancelled', 'Staff Caused');
    INSERT INTO CancellationTypes VALUES('Cancelled', 'Misc');
    INSERT INTO CancellationTypes VALUES('Not Cancelled', 'Completed');
    INSERT INTO CancellationTypes VALUES('Not Cancelled', 'Partially Completed');
    
    --
    -- No changes here...
    --
    
    INSERT INTO Jobs VALUES('20140301', 'Cancelled',     'Weather');
    INSERT INTO Jobs VALUES('20140301', 'Cancelled',     'Weather');
    INSERT INTO Jobs VALUES('20140301', 'Cancelled',     'Equipment Failure');
    INSERT INTO Jobs VALUES('20140301', 'Not Cancelled', 'Completed');
    INSERT INTO Jobs VALUES('20140302', 'Not Cancelled', 'Completed');
    INSERT INTO Jobs VALUES('20140302', 'Not Cancelled', 'Partially Completed');
    INSERT INTO Jobs VALUES('20140305', 'Cancelled',     'Weather');
    INSERT INTO Jobs VALUES('20140305', 'Cancelled',     'Equipment Failure');
    INSERT INTO Jobs VALUES('20140305', 'Cancelled',     'Staff Caused');
    INSERT INTO Jobs VALUES('20140305', 'Not Cancelled', 'Completed');
    INSERT INTO Jobs VALUES('20140305', 'Not Cancelled', 'Partially Completed');
    
    DECLARE @Headers NVARCHAR(158), @Query NVARCHAR(4000);
    
    --
    -- With the CTE we can get our range of dates and use it to create the
    -- columns for the final resultset.
    --
    
    DECLARE @StartDate AS DATE = '20140301', @EndDate DATE = '20140305';
    WITH Dates AS (
        SELECT @StartDate AS Day
        UNION ALL
        SELECT DATEADD(D, 1, Day) FROM Dates WHERE Day < @EndDate
    )
    SELECT @Headers = STUFF((SELECT DISTINCT '],[' + CONVERT(VARCHAR(10), Day, 101) FROM Dates ORDER BY '],[' + CONVERT(VARCHAR(10), Day, 101) FOR XML PATH('')), 1, 2, '') + ']';
    
    SET @Query =
    'SELECT State, Status, ' + @Headers + ' FROM
    (
        SELECT
            CONVERT(VARCHAR(10), J.Date, 101) AS Date,
            CT.State,
            CT.Reasons AS Status
        FROM CancellationTypes AS CT
        -- This can give us cancellation types with 0 jobs.
        LEFT JOIN Jobs AS J ON CT.Reasons = J.Status AND CT.State = J.State
    ) t
    PIVOT (COUNT(Date) FOR Date IN (' + @Headers + ')) AS pvt ORDER BY pvt.State'
    
    EXECUTE (@Query);
    
    --
    -- We're done here...
    --
    DROP TABLE Jobs;
    DROP TABLE CancellationTypes;
    

    ... and the results:

    
    State         Status              03/01/2014  03/02/2014  03/03/2014  03/04/2014  03/05/2014
    ------------- ------------------- ----------- ----------- ----------- ----------- -----------
    Cancelled     Equipment Failure   1           0           0           0           1
    Cancelled     Misc                0           0           0           0           0
    Cancelled     Staff Caused        0           0           0           0           1
    Cancelled     Weather             2           0           0           0           1
    Not Cancelled Completed           1           1           0           0           1
    Not Cancelled Partially Completed 0           1           0           0           1
    

    Hope this helps.