Pivot n times for Select statement in T-SQL - sql

DECLARE
#StartDate DATE,
#EndDate DATE,
#NumMonths INT,
SET #NumMonths = 12
SET #StartDate = DATEADD(m, -#NumMonths, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
SET #EndDate = DATEADD(m, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
SELECT ROW_NUMBER() OVER (ORDER BY SignUpDate) RowNum, SignUpDate,
TotalSignUp / TotalSignUp M1,
--M2 / TotalSignUp M2,
--M3 / TotalSignUp M3,
--M4 / TotalSignUp M4,
--M5 / TotalSignUp M5,
--M6 / TotalSignUp M6,
--M7 / TotalSignUp M7,
--M8 / TotalSignUp M8,
--M9 / TotalSignUp M9,
--M10 / TotalSignUp M10,
--M11 / TotalSignUp M11,
--M12 / TotalSignUp M12
FROM (
SELECT SignUpDate,
COUNT(DISTINCT ClientID) TotalSignUp,
SUM(CASE WHEN MonthActive = DATEADD(m, 1, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M2,
SUM(CASE WHEN MonthActive = DATEADD(m, 2, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M3,
SUM(CASE WHEN MonthActive = DATEADD(m, 3, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M4,
SUM(CASE WHEN MonthActive = DATEADD(m, 4, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M5,
SUM(CASE WHEN MonthActive = DATEADD(m, 5, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M6,
SUM(CASE WHEN MonthActive = DATEADD(m, 6, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M7,
SUM(CASE WHEN MonthActive = DATEADD(m, 7, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M8,
SUM(CASE WHEN MonthActive = DATEADD(m, 8, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M9,
SUM(CASE WHEN MonthActive = DATEADD(m, 9, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M10,
SUM(CASE WHEN MonthActive = DATEADD(m, 10, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M11,
SUM(CASE WHEN MonthActive = DATEADD(m, 11, DATEADD(MONTH, DATEDIFF(MONTH, 0, #StartDate), 0)) THEN 1.0 ELSE 0.0 END) M12
How can I perform a loop for the select statement so that I can dynamically produce the number of M select statements as set by the #numMonths variable?
e.g., I will want the user of the report to be able to select the #numMonths as an input variable and they could say, want to go back 6 months, or 24 months. I would want the select statement to dynamically pivot in a loop depending on what the #numMonths value is.
To put it in other words I don't want to type out M1-M36 36 times just in case the user wants to go back 3 years, that will look so messy. I want a 1 line 'template' and a Counter + 1 until it reaches the number of #numMonths

DROP TABLE IF EXISTS ##TimePeriods
GO
DECLARE
#StartDate DATE,
#EndDate DATE,
#NumMonths INT,
#SQL NVARCHAR(MAX)
SET #NumMonths = 5
SET #StartDate = DATEADD(m, -#NumMonths, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
SET #EndDate = DATEADD(m, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
;WITH TimePeriods AS
(
SELECT #StartDate AS TheDate
UNION ALL
SELECT DATEADD(m,1,TheDate) FROM TimePeriods
WHERE TheDate < #EndDate
)
SELECT * INTO ##TimePeriods FROM TimePeriods
DECLARE #ColList VARCHAR(MAX) = ''
SELECT #ColList = STRING_AGG(QUOTENAME(TheDate),',')
FROM ##TimePeriods
SET #SQL =
'
SELECT
*
FROM
(
SELECT 1 AS TheData, *
FROM ##TimePeriods
-- JOIN YOUR DATA IN HERE
) SourceData
PIVOT
(MAX(TheData)
FOR TheDate IN ('+#ColList+')
)
AS PivotTable
'
EXEC (#SQL)

Related

How to get value 0 if the result of sql select except statement return no records?

I have a problem with the SQL Except statement, in my case, I select two columns and one column can have values and the others cannot have because the count of the first SQL statement equals the count of the second SQL after the except statement.
Result that I got :
GroupId absences
1 3
Expected result
GroupId absences
1 3
2 0
How can I do in this case?
select
groupId,
(case when groupId = null then 0 else COUNT(*) end) as absence
from (
select
groupId,
COUNT(*) as absences1
from (
select distinct
MONTh,
DAY,
e.groupId
from employee_c c,
holiday hl,
employee e,
groups,
Get_Calendar_Date(
DATEADD(MONTH, DATEDIFF(MONTH, 0, CAST(DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AS datetime)) + #Month - 1, 0),
DATEADD(MONTH, DATEDIFF(MONTH, -1, CAST(DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AS datetime)) + #Month-1, -1)
)
where DATENAME(DD, Weekday) IN (
select WorkingdayId+1
from timetable s,
groups ds,
grouptime de
where dd.groupId = ds.groupId
and dd.groupId = de.groupId
and s.timetableId = de.timetableId
and de.groupId = ds.groupdId)
and DATEPART(MM,hl.startDate) = #Month
and c.isActive=1
except
(select Month,
Day,
d.departmentId
from department d,
Get_Calendar_Date(
DATEADD(MONTH, DATEDIFF(MONTH, 0, CAST(DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AS datetime)) + #Month - 1, 0),
DATEADD(MONTH, DATEDIFF(MONTH, -1, CAST(DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) AS datetime)) + #Month - 1, -1)
),
holiday hle,
employee_c c,
employee e
where datepart(MM,hle.startDate) = #Month
and cast(Date as date) between hle.startDate and hle.endDate
and c.isActive=1
and d.groupId =e.groupId
and c.employeeId=e.employeeId
and c.isActive=1
)
) sc
group by Month,Day,groupId
) s
group by groupId

How to return just the yyyy-mm-dd from the following SQL queries [duplicate]

This question already has answers here:
How to get a date in YYYY-MM-DD format from a TSQL datetime field?
(25 answers)
Closed 4 years ago.
Below are the queries I created. Query #1 returns 2018-07-06 00:00:00.000 and query #2 returns 2018-07-31 23:59:59.997.
I can't figure out how to modify the queries so that they'll return the result in the yyyy-mm-dd format. Please advice.
Query #1 - get fifth business day of the month
SELECT
FifthWeekDay = DATEADD(dd, CASE
WHEN DATEDIFF(dd, -1, ca.FirstOfMonth) % 7 > 1 -- -1 is a Sunday
THEN 7
ELSE 6 - DATEDIFF(dd, -1, ca.FirstOfMonth) % 7 -- -1 is a Sunday
END, ca.FirstOfMonth - 1)
FROM
(SELECT
DATEADD(mm, (SELECT DATEPART(YEAR, GETDATE())) * 12 - 22801 +
(SELECT DATEPART(M, GETDATE())), 0)) ca(FirstOfMonth)
Query #2 - get last business day of the month
SELECT
DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0))
- CASE DATENAME(dw, DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)))
WHEN 'SUNDAY' THEN 2
WHEN 'SATURDAY' THEN 1
ELSE 0
END AS LastBusinessCurrentMonth
You can subquery the results you already have and add a cast( as date):
SELECT CAST(LastBusinessCurrentMonth AS DATE) AS LastBusinessCurrentMonth FROM(
SELECT
DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0))
- CASE DATENAME(dw, DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)))
WHEN 'SUNDAY' THEN 2
WHEN 'SATURDAY' THEN 1
ELSE 0
END AS LastBusinessCurrentMonth) AS X
SELECT CAST(FIFTHWEEKDAY AS DATE) AS FIFTHWEEKDAY FROM(
SELECT
FifthWeekDay = DATEADD(dd, CASE
WHEN DATEDIFF(dd, -1, ca.FirstOfMonth) % 7 > 1 -- -1 is a Sunday
THEN 7
ELSE 6 - DATEDIFF(dd, -1, ca.FirstOfMonth) % 7 -- -1 is a Sunday
END, ca.FirstOfMonth - 1)
FROM
(SELECT
DATEADD(mm, (SELECT DATEPART(YEAR, GETDATE())) * 12 - 22801 +
(SELECT DATEPART(M, GETDATE())), 0)) ca(FirstOfMonth)) AS X
Or you could declare a variable as Date and set the results of your queries to that variable :
DECLARE #DATEVAR DATE
SET #DATEVAR =(
SELECT
DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0))
- CASE DATENAME(dw, DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)))
WHEN 'SUNDAY' THEN 2
WHEN 'SATURDAY' THEN 1
ELSE 0
END AS LastBusinessCurrentMonth)
SELECT #DATEVAR AS LastBusinessCurrentMonth
SET #DATEVAR = (SELECT
DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0))
- CASE DATENAME(dw, DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)))
WHEN 'SUNDAY' THEN 2
WHEN 'SATURDAY' THEN 1
ELSE 0
END AS LastBusinessCurrentMonth)
SELECT #DATEVAR AS LastBusinessCurrentMonth

removing nulls in case statement

I am trying to return the current Monday along with previous monday's data. I want to roll up my nulls or 0000 to have one record return.
select
da.Customer,
sum(case
when DAteadd(wk, datediff(wk, 0, Getdate()), 1) = d.FullDate
then (da.[USD - Balance])
else 0
end) as MondayofCurrentWeek,
sum(case
when DAteadd(wk, datediff(wk, 0, Getdate() - 7), 1) = d.FullDate
then (da.[USD - Balance])
else 0
end) as PreviousMonday
from
Dataset_DemandArchive da
inner join
Dimdate d on d.DateNameUS = da.CREDAT_0
where
da.CREDAT_0 in (dateadd(wk, datediff(wk, 0, Getdate()), 1),
dateadd(wk, datediff(wk, 0, Getdate() - 7), 1))
group by
Customer, FullDate
order by
1
Why not just use window functions?
select da.*
from (select da.Customer, d.FullDate,
sum(da.[USD - Balance]) as MondayCurrentWeek
lag(sum(da.[USD - Balance]), 7) over (partition by da.Customer order by d.FullDate)
from Dataset_DemandArchive da join
Dimdate d
on d.DateNameUS = da.CREDAT_0
group by Customer, FullDate
) da
where da.CREDAT_0 = dateadd(week, datediff(week, 0, Getdate()), 1)

Select top 50 rows in sql server

I have below T-SQL code used in SQL Server 2014.
This code produces 1000s of rows. But i need only top 50 rows (from Supplier Column) from this.
In the below code, if I use SELECT Top 50 s.[CusNo] Supplier then I am not getting desired results.
What changes needs to be done in the below code in order to get only Top 50 rows (of Supplier column) with out any change in the existing result.
SELECT s.[CusNo] Supplier,
RTRIM(CAST(s.[Customer] AS VARCHAR(50)) ) AS Name,
s.[ConcessionNo] Concession,
RTRIM(CAST(s.[ConcessionName] AS VARCHAR(50)) ) AS ConcessionName,
sum(case when s.Date between convert(date,dateadd(wk, datediff(wk, 0, getdate()) - 1, 0) - 1) and convert(date,dateadd(wk, datediff(wk, 0, getdate()) - 1, 0) + 5)
then s.SELLINC else 0 end) ActualSales,
sum(case when s.Date between convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) -1 /* On 14/Feb/2021 modify +6 to -1 */) and convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) + 5 /* On 14/Feb/2021 modify +12 to +5 */)
then s.SELLINC else 0 end) LastYrVariance,
(sum(case when s.Date between convert(date,dateadd(wk, datediff(wk, 0, getdate()) - 1, 0) - 1) and convert(date,dateadd(wk, datediff(wk, 0, getdate()) - 1, 0) + 5) then s.SELLINC else 0 end))-
(sum(case when s.Date between convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) -1 /* On 14/Feb/2021 modify +6 to -1 */) and convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) + 5 /* On 14/Feb/2021 modify +12 to +5 */) then s.SELLINC else 0 end)) LastYrVariancePounds,
(IsNull(sum(case when s.Date between convert(date,dateadd(wk, datediff(wk, 0, getdate()) - 1, 0) - 1) and convert(date,dateadd(wk, datediff(wk, 0, getdate()) - 1, 0) + 5)
then s.SELLINC else 0 end)-sum(case when s.Date between convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) -1 /* On 14/Feb/2021 modify +6 to -1 */) and convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) + 5 /* On 14/Feb/2021 modify +12 to +5 */)
then s.SELLINC else 0 end),0)/NullIf(sum(case when s.Date between convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) -1 /* On 14/Feb/2021 modify +6 to -1 */) and convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) + 5 /* On 14/Feb/2021 modify +12 to +5 */)
then s.SELLINC else 0 end),0))*100 LastYrVariancePercentage,
sum(case when s.Date
BETWEEN
convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(GetDate()) = 1 THEN CONVERT(VARCHAR(4), GetDate(), 112) - 1 ELSE CONVERT(VARCHAR(4), GetDate(), 112) END), 112) + '0101')), 30)) / 7 * 7, '19000107'), 120)
AND
Convert(date, dateadd(wk, datediff(wk, 0, GETDATE()) - 1, 0) + 5)
then s.SELLINC else 0 end) YrToDateActual,
sum(case when s.Date
BETWEEN
convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(DATEADD(year,-1,GetDate())) = 1 THEN CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) - 1 ELSE CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) END), 112) + '0101')), 30)) / 7 * 7, '19000107'), 120)
AND
convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) + 5 /* On 14/Feb/2021 modify +12 to +5 */)
then s.SELLINC else 0 end) LastYrToDateActual,
(sum(case when s.Date
BETWEEN
convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(GetDate()) = 1 THEN CONVERT(VARCHAR(4), GetDate(), 112) - 1 ELSE CONVERT(VARCHAR(4), GetDate(), 112) END), 112) + '0101')), 30)) / 7 * 7, '19000107'), 120)
AND
Convert(date, dateadd(wk, datediff(wk, 0, GETDATE()) - 1, 0) + 5)
then s.SELLINC else 0 end))
-
(sum(case when s.Date
BETWEEN
convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(DATEADD(year,-1,GetDate())) = 1 THEN CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) - 1 ELSE CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) END), 112) + '0101')), 30)) / 7 * 7, '19000107'), 120)
AND
convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) + 5 /* On 14/Feb/2021 modify +12 to +5 */)
then s.SELLINC else 0 end)) YrToDateVariancePounds,
((IsNull
(
(sum(case when s.Date
BETWEEN
convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(GetDate()) = 1 THEN CONVERT(VARCHAR(4), GetDate(), 112) - 1 ELSE CONVERT(VARCHAR(4), GetDate(), 112) END), 112) + '0101')), 30)) / 7 * 7, '19000107'), 120)
AND
Convert(date, dateadd(wk, datediff(wk, 0, GETDATE()) - 1, 0) + 5)
then s.SELLINC else 0 end))
-
(sum(case when s.Date
BETWEEN
convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(DATEADD(year,-1,GetDate())) = 1 THEN CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) - 1 ELSE CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) END), 112) + '0101')), 30)) / 7 * 7, '19000107'), 120)
AND
convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) + 5 /* On 14/Feb/2021 modify +12 to +5 */)
then s.SELLINC else 0 end))
,0)
)
/
(NullIf
(
sum(case when s.Date
BETWEEN
convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(DATEADD(year,-1,GetDate())) = 1 THEN CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) - 1 ELSE CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) END), 112) + '0101')), 30)) / 7 * 7, '19000107'), 120)
AND
convert(date,dateadd(wk, datediff(wk, 0, dateadd(YEAR, - 1, getdate())) - 1, 0) + 5 /* On 14/Feb/2021 modify +12 to +5 */)
then s.SELLINC else 0 end)
,0)))*100 LastYrToDateVariancePercentage
FROM [dbo].[CustomerReports] s
WHERE s.BRN = 1 or s.BRN = 2 or s.BRN = 3 or s.BRN = 4 or s.BRN = 5 or s.SELLINC is null or s.SELLINC = '0'
GROUP BY s.[CusNo], s.[Customer], s.ConcessionNo, s.ConcessionName
order by YrToDateActual desc
When I run this Query In SSRS I get below results (Which is Correct). But displays all the data.
if I use SELECT Top 50 s.[CusNo] Supplier (Rest of the code is same) then I am getting the below,
So please see the highlighted section in both the images. When I add Top 50 in SQL code then few rows (in 3rd column ) which were present in 1st image is not present in 2nd image.
Try this:
With cte as (**your long query goes here**)
Select Top(50) * From cte
The sort order in your query is by YrToDateActual desc, so the TOP 50 is giving you the highest 50 YrToDateActual amounts. Your SSRS report is grouping by Supplier number and name, but doesn't look to be sorting by either of these columns, so I'm guessing that the order of these suppliers is somewhat random in the SSRS output. In this case I don't think you're ever going to be able to get the first 50 rows of your original SSRS output. The best you could do would be to also sort your SSRS output (e.g. by Supplier number) and then add this sort into your query (order by Supplier, YrToDateActual desc). Adding the TOP 50 into your query would cut off your new sorted SSRS output after the first 50 results.
What do you want to see in the report? Do you want to see the top 50 suppliers based on their total value (e.g. Actual £ Total) and then all the Concessions (as per your first screenshot) ?
If so, you will need to rank the suppliers by their total and select any that are rank 50 or below.
Here's a very simplified example that might help. In this I've used SUM() OVER() rather than using GROUP BY but this means you might want to change the SELECT to SELECT DISTINCT depending on you needs as you will get lots of duplicate rows. Obviously it's not got your lengthy case statements in but you should be able to adapt it easily.
SELECT * FROM
(
SELECT
x.*
, DENSE_RANK() OVER(ORDER BY SupplierTotal DESC) as SupplierRank
, DENSE_RANK() OVER(PARTITION BY SupplierID ORDER BY ConcessionTotal DESC) as ConcessionRank
FROM
( SELECT DISTINCT
SupplierID, ConcessionID, MyOtherRequiredColumns,
SUM(myValue) OVER(PARTITION BY SupplierID) AS SupplierTotal,
SUM(myValue) OVER(PARTITION BY SupplierID, ConcessionID) AS ConcessionTotal
FROM MyTable
) x
) z
WHERE SupplierRank <= 50
This will also rank the concessions within supplier which might be useful..
You will also have to change you report where you have summed the values up (e.g. 99,389 in Actual £ column). Instead of summing the rows below, change the expression to be =FIRST(Fields!SupplierTotal.Value)

How do I PIVOT this SQL to achieve the desired result?

I have a stored proc that produces a table like this:
PeriodStart PeriodEnd TotalActive TotalAdded TotalRemoved
2011-03-01 2011-03-07 123 456 789
2011-03-08 2011-03-14 567 789 123
2011-03-15 2011-03-21 444 555 666
etc...
I need to display the results in a table that looks like this:
03-01-2011 03-08-2011 03-15-2011
Active 123 567 444
Added 456 789 555
Removed 789 123 666
I've never had to use PIVOT before so I'm a little unsure of how to modify the below SQL in order to achieve the desired result. Here's the sproc:
ALTER PROCEDURE [dbo].[TrendReport]
#DateStart datetime,
#DateEnd datetime,
#Frequency varchar(5)
AS
BEGIN
SELECT
PeriodStart,
PeriodEnd,
SUM(TotalActive) As TotalActive,
SUM(TotalAdded) As TotalAdded,
SUM(TotalRemoved) As TotalRemoved
FROM (
SELECT
PeriodStart = CASE #Frequency
WHEN 'day' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, [Date]))
WHEN 'week' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(DAY, 1 - DATEPART(WEEKDAY, [Date]), [Date])))
WHEN 'month' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0)))
WHEN 'quarter' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, [Date]), 0)))
WHEN 'year' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(YEAR, DATEDIFF(YEAR, 0, [Date]), 0)))
END,
PeriodEnd = CASE #Frequency
WHEN 'day' THEN DATEADD(s, -1, DATEADD(day, 1, DATEDIFF(DAY, 0, [Date])))
WHEN 'week' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, 7 - DATEPART(WEEKDAY, [Date]), [Date]))))
WHEN 'month' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]) + 1, 0)))))
WHEN 'quarter' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, [Date]) + 1, 0)))))
WHEN 'year' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, [Date]) + 1, 0)))))
END,
TotalActive,
TotalAdded,
TotalRemoved
FROM TrendReport P
WHERE [Date] BETWEEN #DateStart AND #DateEnd
) s
GROUP BY
PeriodStart,
PeriodEnd
ORDER BY PeriodStart
END
You actually need to first apply UNPIVOT to rotate the three quantity types from columns to rows and then apply PIVOT to rotate the period start date to columns and aggregate the quantities.
Here's the thing with using the PIVOT operator though, you need to know what columns you will have ahead of time (03-01-2011, 03-08-2011, 03-15-2011), it will need hard coded into the query (unless you want to get down and dirty with dynamic sql, which i would read up on before using in production)
Here is the solution:
WITH CTE AS (
SELECT
PeriodStart,
PeriodEnd,
SUM(TotalActive) As TotalActive,
SUM(TotalAdded) As TotalAdded,
SUM(TotalRemoved) As TotalRemoved
FROM (
SELECT
PeriodStart = CASE #Frequency
WHEN 'day' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, [Date]))
WHEN 'week' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(DAY, 1 - DATEPART(WEEKDAY, [Date]), [Date])))
WHEN 'month' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0)))
WHEN 'quarter' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, [Date]), 0)))
WHEN 'year' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(YEAR, DATEDIFF(YEAR, 0, [Date]), 0)))
END,
PeriodEnd = CASE #Frequency
WHEN 'day' THEN DATEADD(s, -1, DATEADD(day, 1, DATEDIFF(DAY, 0, [Date])))
WHEN 'week' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, 7 - DATEPART(WEEKDAY, [Date]), [Date]))))
WHEN 'month' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]) + 1, 0)))))
WHEN 'quarter' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, [Date]) + 1, 0)))))
WHEN 'year' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, [Date]) + 1, 0)))))
END,
TotalActive,
TotalAdded,
TotalRemoved
FROM TrendReport P
WHERE [Date] BETWEEN #DateStart AND #DateEnd
) s
GROUP BY
PeriodStart,
PeriodEnd
ORDER BY PeriodStart
), U AS (
SELECT qty_type, PeriodStart, qty
FROM CTE
UNPIVOT(qty FOR qty_type IN([TotalActive], [TotalAdded], [TotalRemoved]))Q
)
SELECT * FROM U
PIVOT (SUM(Qty) FOR PeriodStart IN([03/01/2011], [03/08/2011], [03/15/2011])) AS P
I do not have an instance of SQL on my machine at the moment, so this may have some problems with syntax. However, give this a try...it is my attempt at the craftiness via dynamic SQL that J Cooper referred to:
CREATE TABLE #Temp1 (ID INT IDENTITY(1,1), PeriodStart DATETIME, PeriodEnd DATETIME, TotalActive INT, TotalAdded INT, TotalRemoved INT)
INSERT INTO #Temp1 (PeriodStart, PeriodEnd, TotalActive, TotalAdded, TotalRemoved)
SELECT
PeriodStart,
PeriodEnd,
TotalActive,
TotalAdded,
TotalRemoved
FROM (
SELECT
PeriodStart = CASE #Frequency
WHEN 'day' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, [Date]))
WHEN 'week' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(DAY, 1 - DATEPART(WEEKDAY, [Date]), [Date])))
WHEN 'month' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0)))
WHEN 'quarter' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, [Date]), 0)))
WHEN 'year' THEN DATEADD(hour, 0, DATEDIFF(DAY, 0, DATEADD(YEAR, DATEDIFF(YEAR, 0, [Date]), 0)))
END,
PeriodEnd = CASE #Frequency
WHEN 'day' THEN DATEADD(s, -1, DATEADD(day, 1, DATEDIFF(DAY, 0, [Date])))
WHEN 'week' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, 7 - DATEPART(WEEKDAY, [Date]), [Date]))))
WHEN 'month' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]) + 1, 0)))))
WHEN 'quarter' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, [Date]) + 1, 0)))))
WHEN 'year' THEN DATEADD(s, -1, DATEADD(hour, 0, DATEDIFF(DAY, -1, DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, [Date]) + 1, 0)))))
END,
TotalActive,
TotalAdded,
TotalRemoved
FROM TrendReport P
WHERE [Date] BETWEEN #DateStart AND #DateEnd
) s
GROUP BY
PeriodStart,
PeriodEnd
ORDER BY PeriodStart
DECLARE #CreatePivot VARCHAR(MAX), #PivotColumns VARCHAR(MAX)
SET #CreatePivot = 'CREATE TABLE #Temp2 (BaseColumn VARCHAR(25)'
DECLARE #Count INT, #CurrentDateBeingChecked DATETIME
SET #Count = 1
WHILE(SELECT COUNT(*) FROM #Temp1 WHERE ID >= #Count) > 0
BEGIN
SELECT #CurrentDateBeingChecked = PeriodStart FROM #Temp1 WHERE ID = #Count
IF #Count > 1
SET #PivotColumns = #PivotColumns + ','
SET #PivotColumns = #PivotColumns + '[' + CAST(#CurrentDateBeingChecked AS VARCHAR(15) + ']'
SET #CreatePivot = #CreatePivot + ', [' + CAST(#CurrentDateBeingChecked AS VARCHAR(15) + '] INT'
SET #Count = #Count + 1
END
SET #CreatePivot = #CreatePivot + ')'
sp_executesql(#CreatePivot)
DECLARE #PivotStatementToRun VARCHAR(MAX)
SET #PivotStatementToRun =
'
INSERT INTO #Temp2
SELECT 'Active' AS BaseColumn,
' + #PivotColumns + '
FROM
(SELECT PeriodStart, TotalActive
FROM #Temp1) AS SourceTable
PIVOT
(
SUM(TotalActive)
FOR PeriodStart IN (
' + #PivotColumns + ')
) AS PivotTable;
'
sp_executesql(#PivotStatementToRun)
SET #PivotStatementToRun =
'
INSERT INTO #Temp2
SELECT 'Added' AS BaseColumn,
' + #PivotColumns + '
FROM
(SELECT PeriodStart, TotalAdded
FROM #Temp1) AS SourceTable
PIVOT
(
SUM(TotalAdded)
FOR PeriodStart IN (
' + #PivotColumns + ')
) AS PivotTable;
'
sp_executesql(#PivotStatementToRun)
SET #PivotStatementToRun =
'
INSERT INTO #Temp2
SELECT 'Removed' AS BaseColumn,
' + #PivotColumns + '
FROM
(SELECT PeriodStart, TotalRemoved
FROM #Temp1) AS SourceTable
PIVOT
(
SUM(TotalRemoved)
FOR PeriodStart IN (
' + #PivotColumns + ')
) AS PivotTable;
'
sp_executesql(#PivotStatementToRun)
SELECT * FROM #Temp2