Problem: Compare data of a given date range to the same data of up to 3 previous years, and display the tabular data and a graph in an SSRS report. However currently, my stored procedure that I have made for the SSRS report doesn’t work, as it uses temp tables, which aren’t exposed to SSRS. I totally get why, SSRS has no clue about the structures on the temp tables I’ve created.
For example, I want to see the count widgets made from 01/01/2012 to 04/01/2012, grouped by hour.
So the logical layout of the table is:
Hour Count
0 100
1 240
2 34
3 24
4 55
5 90
…
23 7657
So for that data, I want to compare it to how the plant did the previous year(s) (up to 3), for the same date range.
It seems so simple, yet the solution that I came up with, is anything but.
I’ve worked it out so that, I have a table-valued function that calculates the required data for the given start_date and end_dates, and pulls the data from the source table. I believe that is the right way to do it?
ALTER FUNCTION [dbo].[Count_TS] (@SDate DATETIME2,@EDate DATETIME2)
RETURNS @t TABLE ([Hour] INT,[Count] INT) AS
BEGIN
INSERT @t ([Hour],[Count])
SELECT DATEPART(HOUR,AC.[FIELDC]) AS [Hour],COUNT(DISTINCT(AC.[FIELDD])) AS [CFS_Count_1]
FROM [LINKEDSERVER].[DATABASE].[dbo].[TABLE] AS AC WITH (NOLOCK)
WHERE (AC.[FIELDA] LIKE 'VALUE' OR AC.[FIELDA] LIKE 'VALUE')
AND AC.[FIELDB] = 'VALUE'
AND (CAST(AC.[FIELDC] AS DATE) >= @SDate AND CAST(AC.[FIELDC] AS DATE) <= @EDate)
GROUP BY DATEPART(HOUR,AC.[FIELDC])
RETURN
END
The bit where it goes downhill is the manner in which I have constructed the stored procedure to display the data in the SSRS report. The stored proc doesn’t need explaining, it’s fairly evident of what I have done. Which it cannot be the “right” way to do this?
ALTER PROCEDURE [rptCount_TS]
@PREYears INT = NULL
,@SDate DATE = NULL
,@EDate DATE = NULL
AS
BEGIN
IF DATEDIFF(MONTH,@SDate,@EDate) <=3 AND DATEDIFF(YEAR,@SDate,@EDate) =0
BEGIN
IF @PREYears = 0
BEGIN
IF OBJECT_ID('tempdb..#CountPrime') IS NOT NULL DROP TABLE dbo.[#CountPrime];
CREATE TABLE #CountPrime ([Hour] INT,[CountPrime] INT)
INSERT INTO #CountPrime([Hour], [CountPrime])
SELECT [Hour],[Count] FROM [Connector].dbo.[Count_TS] (@SDate,@EDate)
SELECT CCP.[Hour]
,CCP.[CountPrime]
FROM #CountPrime AS CCP
END
ELSE
IF @PREYears =1
BEGIN
IF OBJECT_ID('tempdb..#CountPrime1') IS NOT NULL DROP TABLE dbo.[#CountPrime1];
CREATE TABLE #CountPrime1 ([Hour] INT,[CountPrime] INT)
IF OBJECT_ID('tempdb..#Count-11') IS NOT NULL DROP TABLE dbo.[#Count-11];
CREATE TABLE [#Count-11] ([Hour] INT,[Count-1] INT)
INSERT INTO #CountPrime1([Hour], [CountPrime])
SELECT [Hour],[Count] FROM [Connector].dbo.[Count_TS] (@SDate,@EDate)
INSERT INTO [#Count-11]([Hour], [Count-1])
SELECT [Hour],[Count] AS [Count-1] FROM [Connector].dbo.[Count_TS] (DATEADD(YEAR,-1,@SDate),DATEADD(YEAR,-1,@EDate));
SELECT CCP.[Hour]
,CCP.[CountPrime]
,SC1.[Count-1]
FROM #CountPrime1 AS CCP
INNER JOIN [#Count-11] AS SC1 ON CCP.[Hour] = SC1.[Hour]
END
ELSE
IF @PREYears =2
BEGIN
IF OBJECT_ID('tempdb..#CountPrime2') IS NOT NULL DROP TABLE dbo.[#CountPrime2];
CREATE TABLE #CountPrime2 ([Hour] INT,[CountPrime] INT)
IF OBJECT_ID('tempdb..#Count-12') IS NOT NULL DROP TABLE dbo.[#Count-12];
CREATE TABLE [#Count-12] ([Hour] INT,[Count-1] INT)
IF OBJECT_ID('tempdb..#Count-22') IS NOT NULL DROP TABLE dbo.[#Count-22];
CREATE TABLE [#Count-22] ([Hour] INT,[Count-2] INT)
INSERT INTO #CountPrime2([Hour], [CountPrime]) SELECT [Hour],[Count] FROM [Connector].dbo.[Count_TS] (@SDate,@EDate)
INSERT INTO [#Count-12]([Hour], [Count-1])
SELECT [Hour],[Count] AS [Count-1] FROM [Connector].dbo.[Count_TS] (DATEADD(YEAR,-1,@SDate),DATEADD(YEAR,-1,@EDate));
INSERT INTO [#Count-22]([Hour], [Count-2])
SELECT [Hour],[Count] AS [Count-2] FROM [Connector].dbo.[Count_TS] (DATEADD(YEAR,-2,@SDate),DATEADD(YEAR,-2,@EDate));
SELECT CCP.[Hour]
,CCP.[CountPrime]
,SC1.[Count-1]
,SC2.[Count-2]
FROM #CountPrime2 AS CCP
INNER JOIN [#Count-12] AS SC1 ON CCP.[Hour] = SC1.[Hour]
INNER JOIN [#Count-22] AS SC2 ON CCP.[Hour] = SC2.[Hour]
END
ELSE
IF @PREYears =3
BEGIN
IF OBJECT_ID('tempdb..#CountPrime3') IS NOT NULL DROP TABLE dbo.[#CountPrime3];
CREATE TABLE #CountPrime3 ([Hour] INT,[CountPrime] INT)
IF OBJECT_ID('tempdb..#Count-13') IS NOT NULL DROP TABLE dbo.[#Count-13];
CREATE TABLE [#Count-13] ([Hour] INT,[Count-1] INT)
IF OBJECT_ID('tempdb..#Count-23') IS NOT NULL DROP TABLE dbo.[#Count-23];
CREATE TABLE [#Count-23] ([Hour] INT,[Count-2] INT)
IF OBJECT_ID('tempdb..#Count-33') IS NOT NULL DROP TABLE dbo.[#Count-33];
CREATE TABLE [#Count-33] ([Hour] INT,[Count-3] INT)
INSERT INTO #CountPrime3([Hour], [CountPrime]) SELECT [Hour],[Count] FROM [Connector].dbo.[Count_TS] (@SDate,@EDate)
INSERT INTO [#Count-13]([Hour], [Count-1])
SELECT [Hour],[Count] AS [Count-1] FROM [Connector].dbo.[Count_TS] (DATEADD(YEAR,-1,@SDate),DATEADD(YEAR,-1,@EDate));
INSERT INTO [#Count-23]([Hour], [Count-2])
SELECT [Hour],[Count] AS [Count-2] FROM [Connector].dbo.[Count_TS] (DATEADD(YEAR,-2,@SDate),DATEADD(YEAR,-2,@EDate));
INSERT INTO [#Count-33]([Hour], [Count-3])
SELECT [Hour],[Count] AS [Count-3] FROM [Connector].dbo.[Count_TS] (DATEADD(YEAR,-3,@SDate),DATEADD(YEAR,-3,@EDate));
SELECT CCP.[Hour]
,CCP.[CountPrime]
,SC1.[Count-1]
,SC2.[Count-2]
,SC3.[Count-3]
FROM #CountPrime3 AS CCP
INNER JOIN [#Count-13] AS SC1 ON CCP.[Hour] = SC1.[Hour]
INNER JOIN [#Count-23] AS SC2 ON CCP.[Hour] = SC2.[Hour]
INNER JOIN [#Count-33] AS SC3 ON CCP.[Hour] = SC3.[Hour]
END
END
ELSE
PRINT 'Sorry, at maximum you can only search a 3 month time span.'
If this is the way to do the project, how can I expose the tables inside of the stored proc to SSRS? Do I have to fumble my way through converting it to another TVF? I looked up SET’ing FMTONLY, and sp_describe_first_result_set, but those did not seem like viable solutions. Should I roll up all guts of the stored proc into the first TVF?,can I keep the stored proc and use CTEs in place of temp tables?
Is this what SSAS is for?
Best Answer
I believe you can get what you want by doing the following:
(1) combine function and procedure into 1 select statement
(2) add grouping by Year to single SELECT
(3) I added recursive CTE to generate "HOUR" dimension and use this instead of getting hour from actual data; this will show hours with 0 then
(4) You can add/use SSRS parameter for number of years, pass that to procedure, but also possibly use it to hide columns for years not desired to show on report.