Cumulative sum based on months in a year with NULL Months - sql-server

I am trying to return a summary of all prospects entered in the system for a chosen sales person and a chosen year. The date entered is a datetime and I am pivoting the data to show it broken by month to month.
The first query returns the number of referrals each month, where the second query shows how many referrals entered cumulatively. I have gotten them properly showing with the exception of months containing null values. Months with null values I want to show the value of the previous month in that case.
I am currently using T-SQL 2012.
SELECT 'Number of Referrals' AS Measure,[1] AS Jan, [2] AS Feb, [3] AS Mar, [4] AS Apr,
[5] AS May, [6] AS Jun, [7] AS Jul, [8] AS Aug, [9] AS Sep, [10] AS Oct, [11] AS Nov, [12] AS Dec
FROM
(
SELECT ISNULL(COUNT(DISTINCT CSCU.ClientID), 0) AS Referrals, DATEPART(M, CS.DateAdded) AS Months
FROM ClientTracker.dbo.ClientService CS
INNER JOIN ClientTracker.dbo.ClientServiceContactUser CSCU
ON CS.ClientID = CSCU.ClientID
AND CS.ServiceID = CSCU.ServiceID
WHERE UserId = #UserID
AND DATEPART(YEAR, CS.DateAdded) = #Year
AND CSCU.ServiceID = 30
GROUP BY DATEPART(M, CS.DateAdded)
) AS S
PIVOT
(
SUM(Referrals)
FOR [Months] IN ([1], [2], [3], [4],
[5], [6], [7], [8], [9], [10], [11], [12])
)AS PV
UNION
SELECT 'Number of Referrals Cumulative' AS Measure,[1] AS Jan, [2] AS Feb, [3] AS Mar, [4] AS Apr, [5] AS May, [6] AS Jun, [7] AS Jul, [8] AS Aug, [9] AS Sep, [10] AS Oct, [11] AS Nov, [12] AS Dec
FROM
(
SELECT DATEPART(M, CS.DateAdded) AS Months,
SUM(COUNT(CSCU.ClientID)) OVER (ORDER BY DATEPART(M, CS.DateAdded)) AS Cumulative
FROM ClientTracker.dbo.ClientService CS
INNER JOIN ClientTracker.dbo.ClientServiceContactUser CSCU
ON CS.ClientID = CSCU.ClientID
AND CS.ServiceID = CSCU.ServiceID
WHERE UserId = #UserID
AND DATEPART(YEAR, CS.DateAdded) = #Year
AND CSCU.ServiceID = 30
GROUP BY DATEPART(M, CS.DateAdded)
) AS S
PIVOT
(
SUM(Cumulative)
FOR [Months] IN ([1], [2], [3], [4],
[5], [6], [7], [8], [9], [10], [11], [12])
)AS PV

You could use coalesce() function. It takes in as many parameters and returns the first non null values.
So for in your example rewrite the query to
SELECT 'Number of Referrals' AS Measure,[1] AS Jan, coalesce([2],[1]) AS Feb, .....
COALESCE() on MSDN

Related

multiple pivot on same column in tsql

How can I have pivot define on same column in tsql?
for example:
SELECT * FROM (
SELECT CAST(start_time AS DATE) AS [Date],
DATEPART(hour,start_time) AS [Hour],
Count(is_sale)AS [Sales Count]
,Count(is_not_sale)AS [No Sales Count]
FROM prov_sales WITH(NOLOCK)
GROUP BY CAST(start_time AS DATE), DATEPART(hour,start_time)) AS HourlySalesData
PIVOT( SUM([Sales Count]) FOR [Hour] IN ([0], [1], [2], [3], [4], [5], [6], [7],
[8], [9], [10],[11], [12], [13], [14], [15], [16],
[17], [18], [19], [20], [21], [22], [23])) AS DatePivot1
PIVOT( SUM([No Sales Count]) FOR [Hour] IN ([0], [1], [2], [3], [4], [5], [6], [7],
[8], [9], [10],[11], [12], [13], [14], [15], [16],
[17], [18], [19], [20], [21], [22], [23])) AS DatePivot2
My above tsql is not working as I am getting error for the hour column which has repeated values from [1] to [23].
As PIVOT creates Column names from the IN list, you cannot define same column like [1] twice. Although the following solution is not a standard one, but it may server your purpose-
SELECT * FROM (
SELECT CAST(start_time AS DATE) AS [Date],
--Created the hour column twice for Pivoting twice
'Sales_' + CAST(DATEPART(hour,start_time) AS VARCHAR) AS [Hour_Sales],
'NoSales_' + CAST(DATEPART(hour,start_time) AS VARCHAR) AS [Hour_NoSales],
Count(is_sale)AS [Sales Count]
,Count(is_not_sale)AS [No Sales Count]
FROM prov_sales WITH(NOLOCK)
GROUP BY CAST(start_time AS DATE), DATEPART(hour,start_time)) AS HourlySalesData
PIVOT( SUM([Sales Count]) FOR [Hour_Sales] IN ([Sales_0], [Sales_1], [Sales_2], [Sales_3], [Sales_4], [Sales_5], [Sales_6], [Sales_7],
[Sales_8], [Sales_9], [Sales_10],[Sales_11], [Sales_12], [Sales_13], [Sales_14], [Sales_15], [Sales_16],
[Sales_17], [Sales_18], [Sales_19], [Sales_20], [Sales_21], [Sales_22], [Sales_23])) AS DatePivot1
PIVOT( SUM([No Sales Count]) FOR [Hour_NoSales] IN ([NoSales_0], [NoSales_1], [NoSales_2], [NoSales_3], [NoSales_4], [NoSales_5], [NoSales_6], [NoSales_7],
[NoSales_8], [NoSales_9], [NoSales_10],[NoSales_11], [NoSales_12], [NoSales_13], [NoSales_14], [NoSales_15], [NoSales_16],
[NoSales_17], [NoSales_18], [NoSales_19], [NoSales_20], [NoSales_21], [NoSales_22], [NoSales_23])) AS DatePivot2

how to Replace null with zero in pivot SQL query

I am trying to fetch Year wise and month wise sales like
select * from
(
select year(InvDt) as [Year], left(datename(Month,InvDt), 3) as [Month],
InvAmnt as Amount
from tblInvoice where TenantId =-xxxxxxxx
) as Inv
pivot
(sum(Amount) for [Month] in(Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep,
Oct, Nov, [Dec])) as pvt
But here so many null is coming so I want to replace these null with zero.
please help me.
create table tblInvoice (InvDt date, TenantId int, InvAmnt numeric)
insert into tblInvoice values ('20180601',1,1),('20180601',1,1),('20180601',1,1),('20180501',1,1), ('20180401',1,1)
SELECT Year
, COALESCE(Jan ,0) Jan
, COALESCE(Feb ,0) Feb
, COALESCE(Mar ,0) Mar
, COALESCE(Apr ,0) Apr
, COALESCE(May ,0) May
, COALESCE(Jun ,0) Jun
, COALESCE(Jul ,0) Jul
, COALESCE(Aug ,0) Aug
, COALESCE(Sep ,0) Sep
, COALESCE(Oct ,0) Oct
, COALESCE(Nov ,0) Nov
, COALESCE(Dec ,0) Dec
FROM ( SELECT YEAR(InvDt) AS Year
, LEFT(DATENAME(MONTH, InvDt), 3) AS Month
, InvAmnt AS Amount
FROM tblInvoice
WHERE TenantId = 1) AS Inv
PIVOT ( SUM(Amount)
FOR Month IN (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec)) AS pvt;
So Answer is this but it's too long, something we must have another solution but I am not getting right now
select [Year], isnull(Jan, 0) as Jan,isnull(Feb,0) as Feb, isnull(Mar, 0) as
Mar, isnull(Apr, 0) as Apr, isnull(May,0) as May,
isnull(Jun,0) as Jun, isnull(Jul,0) as Jul, isnull(Aug,0) as Aug,
isnull(Sep,0) as Sep,isnull(Oct,0) as Oct, isnull(Nov,0) as Nov,
isnull([Dec],0) as Dec
from
(
select year(InvDt) as [Year], left(datename(Month,InvDt), 3) as [Month],
InvAmnt as Amount
from tblInvoice where TenantId =-xxxxxxx
) as Inv
pivot
(sum(Amount) for [Month] in(Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep,
Oct, Nov, [Dec])) as pvt
Thanks Mazhar by your solution my mind was opened and works this.
Just add a coalesce statement in a subquery to replace nulls on zero:
select * from
(
select year(InvDt) as [Year], left(datename(Month,InvDt), 3) as [Month],
coalesce(InvAmnt, 0) as Amount
from tblInvoice where TenantId =-xxxxxxxx
) as Inv
pivot
(sum(Amount) for [Month] in(Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep,
Oct, Nov, [Dec])) as pvt)

PIVOT with Grand Total

I'm working with PIVOT in SQL, something I've only started learning about this week. I'm trying to get a grand total for each Director as an added column at the side. I've looked online and seen its a popular query, but the ways of doing it seem really confusing and a little over-kill for what I need. Can someone show me how I'd add a grand total column at the end of each row that just adds up the monthly numbers for each Director?
SELECT *
FROM (
SELECT
DimDirectoR.Full_Name, YEAR(dim_Date.Date) as [year],left(datename(month,dim_Date.Date),3)as [month],
Fact_Stream.Device_Type_ID as Amount
FROM Fact_Stream INNER JOIN DimDirector ON Fact_Stream.Director_ID=DimDirector.Director_ID
INNER JOIN dim_Date
on Fact_Stream.Request_View_Date = dim_Date.ID
) as Directors
PIVOT
(
COUNT(Amount)
FOR [month] IN (jan, feb, mar, apr,
may, jun, jul, aug, sep, oct, nov, dec)
)AS DirectorsMonthlyStreams
ORDER BY [year], Full_Name
Current output:
I simply want to have a column which says 'Total' at the end of each row displaying the total amount for that directors year...
SQL Server 2012
You can just do a sum in the top level select statement:
SELECT *, jan+feb+mar+apr+may+jun+jul+aug+sep+oct+nov+dec Total
FROM (
SELECT
DimDirectoR.Full_Name, YEAR(dim_Date.Date) as [year],left(datename(month,dim_Date.Date),3)as [month],
Fact_Stream.Device_Type_ID as Amount
FROM Fact_Stream INNER JOIN DimDirector ON Fact_Stream.Director_ID=DimDirector.Director_ID
INNER JOIN dim_Date
on Fact_Stream.Request_View_Date = dim_Date.ID
) as Directors
PIVOT
(
COUNT(Amount)
FOR [month] IN (jan, feb, mar, apr,
may, jun, jul, aug, sep, oct, nov, dec)
)AS DirectorsMonthlyStreams
ORDER BY [year], Full_Name
You could do something like this as well:
SQL - Pivot with Grand Total Column and Row

Return the count of all records per day of week by clientId

I'm trying to write a query that will return the daily count of clients records (for the last 7 days) by client.
Given a table with the following significant fields:
ClientId, ProcessTime,
I'd like to produce a table with the clientId and the last 7 days as column headers 0 - 7 (including today) and the records processed in that day:
ClientId, 0, 1, 2, 3, 4, 5, 6, 7
I have come up with the following query which gets me close:
Select ClientId, Count(Id) as [Count], max(DATEDIFF(DAY,ProcessTime,GETDATE())) as [Day]
from CallRecords
WHERE DATEDIFF(DAY,ProcessTime,GETDATE()) <= 7
group by ClientId, Dateadd(day, Datediff(day, 0, ProcessTime), 0)
order by 1, 2
which produces:
ClientId Count Day
1 60 0
1 4707 1
1 11613 2
However, how can I manipulate those results into a format where I get a list of clients and the last 7 days of results as columns?
SELECT ClientID
,COUNT(CASE WHEN DATEPART(WEEKDAY,ProcessTime) = 1 THEN 1 ELSE NULL END) AS [Sunday]
,COUNT(CASE WHEN DATEPART(WEEKDAY,ProcessTime) = 2 THEN 1 ELSE NULL END) AS [Monday]
,COUNT(CASE WHEN DATEPART(WEEKDAY,ProcessTime) = 3 THEN 1 ELSE NULL END) AS [Tuesday]
,COUNT(CASE WHEN DATEPART(WEEKDAY,ProcessTime) = 4 THEN 1 ELSE NULL END) AS [Wednesday]
,COUNT(CASE WHEN DATEPART(WEEKDAY,ProcessTime) = 5 THEN 1 ELSE NULL END) AS [Thursday]
,COUNT(CASE WHEN DATEPART(WEEKDAY,ProcessTime) = 6 THEN 1 ELSE NULL END) AS [Friday]
,COUNT(CASE WHEN DATEPART(WEEKDAY,ProcessTime) = 7 THEN 1 ELSE NULL END) AS [Saturday]
FROM CallRecords
WHERE ProcessTime >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 7, 0)
GROUP BY ClientID
You want what is termed a pivot, which SQLServer natively supports:
select ClientId, [0], [1], [2], [3], [4], [5], [6], [7]
from (select ClientId, DATEDIFF(DAY,ProcessTime,GETDATE()) days
from CallRecords
where DATEDIFF(DAY,ProcessTime,GETDATE()) <= 7) t
pivot (count(days) for days in ([0], [1], [2], [3], [4], [5], [6], [7])) pt
SQLFiddle
Pivot is the way to go for this scenario. Here is a link to Microsofts pivot documentation, Microsoft PIVOT. To find the day of the week you should use the DatePart function, Microsoft DatePart Function
select ClientId as 'Client', [1], [2], [3], [4], [5], [6], [7] from (
select ClientId, Id, CAST(DatePart(dw,ProcessTime) as int) as [DayOfWeek]
from CallRecords
) as SourceTable
PIVOT (
COUNT(Id)
FOR [DayOfWeek] IN ([1], [2], [3], [4], [5], [6], [7])
) as pvt
Checkout this SQLFiddle

MDX query for average of sums by month and year

I'm stuck on a MDX query... I have a table which looks like:
Date Client Amount
---------------------------------
2010-01-01 1 1000
2010-01-01 2 500
2010-01-02 1 1100
... ... ...
2011-09-30 3 2000
Basically, I'd like to have a MDX equivalent of the following T-SQL:
SELECT [Year], [Month], AVG(DailyTotal)
FROM (
SELECT [Year], [Month], [Day], SUM(Amount) as DailyTotal
FROM Table
GROUP BY [Year], [Month], [Day]
)
GROUP BY [Year], [Month]
I'm trying to get as result like
Jan ... Sept
2010 AVG ... AVG
2011 AVG ... AVG
Thanks in advance
I have a query using Adventure Works:
with member [measures].[Average] as Avg({Descendants([Date].[Calendar].CurrentMember, [Date].[Calendar].[Date])*[Date].[Month of Year].CurrentMember}, [Measures].[Internet Sales Amount])
select
{{[Date].[Month of Year].[Month of Year]}*{[Measures].[Internet Sales Amount], [measures].[Average]}} on columns,
{[Date].[Calendar].[Calendar Year]} on rows
From [Adventure Works]
In this query I'm using 2 hierarchies ([Date].[Calendar] and [Date].[Month of Year]). Maybe, in your case, you could need do something else if your time dimension have others hierarchies.
select *
from
(
select [Year], [Month], avg(DailyTotal) as AVERAGE
from (
select
[Year] = year([date]),
[Month] = month([date]),
[day] = day([date]) ,
[DailyTotal] = sum([Amount])
from [Table]
group by year(date), month(date), day(date)
) Q
group by [Year], [Month]
) K
pivot (max(AVERAGE) for K.[Month] in ([1],[2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12])) as S

Resources