SQL Pivot table not returining expected results - sql

This is the first time I have had to use a SQL pivot table, so I'm not very proficient in getting results with the method, my pivot table is not returning the results I expected and I don't know why...
Here is my instruction:
"Create a sql that will show the total number create [ddateCreated] of patients per branch for each month for 2020 - 2021.
Display Required fields BranchName , Year , Jan , Feb, Mar, Apr, May , Jun , Jul ,Aug , Sept , Oct , Nov , Dec."
so I came up with the below query:
select * from (
select datename(month, b.dDateCreated) as [Month] ,
sName as BranchName ,
datename(Year, b.dDateCreated) as [Year],
p.ipkPatientID from Branch b
inner join Patients p
on p.ifkBranchID=b.ipkBranchID
where (b.dDateCreated BETWEEN '2020-01-01 00:00:00.000'AND '2021-12-31 23:59:59.999')
) as Src
pivot(
count(ipkPatientID)
for [Month] in ([Jan],
[Feb],
[Mar],
[Apr],
[May],
[Jun],
[Jul],
[Aug],
[Sept],
[Oct],
[Nov],
[Dec])
) as Pivot_Table
Here are the results:
BranchName Year Jan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec
Cdldttd dd Fhdftwt wndfplpgy 2020 0 0 0 0 0 0 0 0 0 0 0 0
Ddjdlppmdnt 2020 0 0 0 0 14 0 0 0 0 0 0 0
Ddpn Cdhpnfp 2020 0 0 0 0 0 0 0 0 0 0 0 0
dlmfdn Lpnw Lfchtdnwnhg 2020 0 0 0 0 0 0 0 0 0 0 0 0
dlmfdn Lpnw Mwffkdng 2020 0 0 0 0 0 0 0 0 0 0 0 0
Dnhwwnjflld 2020 0 0 0 0 0 0 0 0 0 0 0 0
dthpwd 2020 0 0 0 0 0 0 0 0 0 0 0 0
fnc and wttpcfwtdt 2020 0 0 0 0 5 0 0 0 0 0 0 0
Fwdhfd Gldn 2020 0 0 0 0 0 0 0 0 0 0 0 0
Hdwhdwt pfffcd 2020 0 0 0 0 0 0 0 0 0 0 0 0
Hpmd jftft 2020 0 0 0 0 91 0 0 0 0 0 0 0
I can't understand why it shows 0's everywhere? i have tried to refactor this query mulptiple times but I cant come right... Also note how there is little data in the Month of May, for some odd reason.
Look at the below query, which is the source of the pivot table:
select datename(month, b.dDateCreated) as [Month] ,
sName as BranchName ,
datename(Year, b.dDateCreated) as [Year],
p.ipkPatientID from Branch b
inner join Patients p
on p.ifkBranchID=b.ipkBranchID
where (b.dDateCreated BETWEEN '2020-01-01 00:00:00.000'AND '2021-12-31 23:59:59.999')
These results look correct?
and there is data for every month... So how would I count the patient id's for every month and display it?

Pretty sure this will correct your issue
Select *
From (
select left(datename(month, b.dDateCreated),3) as [Month] , -- Notice Jan,Feb,Mar
sName as BranchName ,
datename(Year, b.dDateCreated) as [Year],
p.ipkPatientID
from Branch b
inner join Patients p on p.ifkBranchID=b.ipkBranchID
where b.dDateCreated BETWEEN '2020-01-01 00:00:00.000'AND '2021-12-31 23:59:59.997'
) as Src
Pivot( count(ipkPatientID) for [Month] in ([Jan],
[Feb],
[Mar],
[Apr],
[May],
[Jun],
[Jul],
[Aug],
[Sep], -- Notice Sep not Sept
[Oct],
[Nov],
[Dec] ) ) as Pivot_Table

I would recommend pivoting with conditional aggregation rather than using the vendor-specific pivot query. I find that the pivot syntax is less intuitive ; it is also less flexible, and of course not easily portable across databases.
Using conditional aggregation, and starting from your existing working query, you would pivot like so:
select b.sName as BranchName, x.[Year],
sum(case when x.[Month] = 'Jan' then 1 else 0 end) as Jan
sum(case when x.[Month] = 'Feb' then 1 else 0 end) as Feb
-- ... repeat for the following months...
sum(case when x.[Month] = 'Dec' then 1 else 0 end) as Dec
from Branch b
inner join Patients p on p.ifkBranchID = b.ipkBranchID
cross apply ( values (datename(year, b.dDateCreated), datename(month, b.dDateCreated) ) d([Month], [Year])
where b.dDateCreated >= '2020-01-01' and b.dDateCreated < '2022-01-01'
group by b.ifkBranchID, b.sName, x.[Year]
Side notes:
filtering dates is often simpler than with half-open intervals than with between
you probably want to group by the primary key of the branch table (which I assumed is ifkBranchID) ; different branches may have the same name.
I used outer apply to compute the datenames just once rather than repeating the expressions all over the queqry
it is good practice to prefix all columns in the query with the table they belong to

Related

Sum of particular column with month and year with fiscal year from custom date

I have following data in my table:
uniqueId d_date amount
1 2018-02-01 100.25
2 2019-03-01 456.5
3 2018-02-01 455
4 2019-05-01 200.48
5 2018-06-01 100
6 2019-07-01 200
7 2018-12-01 6950
8 2019-02-01 60
9 2020-01-20 100
Now when I enter start date = '2018-03-12' then my fiscal year must start with march 2018 to feb 2019 and so on.
If i enter start date = '2019-05-12' then my fiscal year must start with May 2019 to April 2020
I have tried below query but it is not working properly and also it calculate past year which is 2017 I do not want any data from past year from my entered custom date. So if entered start date = '2018-03-12' then is must start calculation for 2018 and above years only. No past year.
Declare #startdate as date
Declare #monthDate as int
Declare #ownmonth as int
set #startdate = '2018-03-12'
set #monthDate = month(#startdate)
set #ownmonth = 1
select
year(dateadd(month, -#monthDate, d_date)) year,
sum(case when month(d_date) = case when #monthDate+1 > 12 then #ownmonth else #monthDate+1 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+2 > 12 then #ownmonth+1 else #monthDate+2 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+3 > 12 then #ownmonth+2 else #monthDate+3 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+4 > 12 then #ownmonth+3 else #monthDate+4 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+5 > 12 then #ownmonth+4 else #monthDate+5 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+6 > 12 then #ownmonth+5 else #monthDate+6 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+7 > 12 then #ownmonth+6 else #monthDate+7 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+8 > 12 then #ownmonth+7 else #monthDate+8 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+9 > 12 then #ownmonth+8 else #monthDate+9 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+10 > 12 then #ownmonth+9 else #monthDate+10 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+11 > 12 then #ownmonth+10 else #monthDate+11 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+12 > 12 then #ownmonth+11 else #monthDate+12 End then amount end) ,
sum(amount) total
from mytable
group by year(dateadd(month, -#monthDate, amount))
order by year
But above query does not show proper year & month wise data
Now I want output with fiscal year calculation:
Year Mar Apr May Jun July Aug Sept Oct Nov Dec Jan Feb Total
2018 - - - 100 - - - - - 6950 - 60 7110
2019 456.5 - 200.48 - 200 - - - - - 100 - 956.98
I can not use PIVOT as it is not supported in my compact SQL Server version.
How can I do this?
Your rule for a fiscal year is the year's March until the following year's February:
date | fiscal year
... | ...
2018-02-28 | 2017
2018-03-01 | 2018
... | 2018
2019-02-28 | 2018
2019-03-01 | 2019
... | ...
That means when we subtract two months from a date, we get a date the year of which is the fiscal year:
date | date - 2 months | fiscal year
... | ... | ...
2018-02-28 | 2017-12-28 | 2017
2018-03-01 | 2018-01-01 | 2018
... | ... | 2018
2019-02-28 | 2018-12-28 | 2018
2019-03-01 | 2019-01-01 | 2019
... | ... | ...
select
year(dateadd(month, -2, d_date)) as fiscal_year,
sum(case when month(d_date) = 3 then amount else 0 end) as mar,
sum(case when month(d_date) = 4 then amount else 0 end) as apr,
sum(case when month(d_date) = 5 then amount else 0 end) as may,
sum(case when month(d_date) = 6 then amount else 0 end) as jun,
sum(case when month(d_date) = 7 then amount else 0 end) as jul,
sum(case when month(d_date) = 8 then amount else 0 end) as aug,
sum(case when month(d_date) = 9 then amount else 0 end) as sep,
sum(case when month(d_date) = 10 then amount else 0 end) as oct,
sum(case when month(d_date) = 11 then amount else 0 end) as nov,
sum(case when month(d_date) = 12 then amount else 0 end) as dec,
sum(case when month(d_date) = 1 then amount else 0 end) as jan,
sum(case when month(d_date) = 2 then amount else 0 end) as feb,
sum(amount) as total
from mytable
group by year(dateadd(month, -2, d_date))
order by year(dateadd(month, -2, d_date));
If you want to limit this to the fiscal year a given date resides in, add:
where year(dateadd(month, -2, d_date)) = year(dateadd(month, -2, #given_date))
And well, if you want to limit this to the fiscal years beginning with that year, that would of course be:
where year(dateadd(month, -2, d_date)) >= year(dateadd(month, -2, #given_date))
UPDATE: You want a fiscal year to start with the first day of the month of a given date. I.e. If the given date is 1990-04-23, then a fiscal year starts with April. This changes above query only slightly, because rather than subtracting 2 months (for March), we must generalize this to subtracting one month less than the given month.
I am using a modulo operation when comparing months in order not to end up with months 13, 14, etc.
select
year(dateadd(month, - month(#startdate) + 1, d_date)) as fiscal_year,
sum(case when month(d_date) = (month(#startdate) + 0) % 12 then amount else 0 end) as first,
sum(case when month(d_date) = (month(#startdate) + 1) % 12 then amount else 0 end) as second,
sum(case when month(d_date) = (month(#startdate) + 2) % 12 then amount else 0 end) as third,
sum(case when month(d_date) = (month(#startdate) + 3) % 12 then amount else 0 end) as fourth,
sum(case when month(d_date) = (month(#startdate) + 4) % 12 then amount else 0 end) as fith,
sum(case when month(d_date) = (month(#startdate) + 5) % 12 then amount else 0 end) as sixth,
sum(case when month(d_date) = (month(#startdate) + 6) % 12 then amount else 0 end) as seventh,
sum(case when month(d_date) = (month(#startdate) + 7) % 12 then amount else 0 end) as eighth,
sum(case when month(d_date) = (month(#startdate) + 8) % 12 then amount else 0 end) as nineth,
sum(case when month(d_date) = (month(#startdate) + 9) % 12 then amount else 0 end) as tenth,
sum(case when month(d_date) = (month(#startdate) + 10) % 12 then amount else 0 end) as eleventh,
sum(case when month(d_date) = (month(#startdate) + 11) % 12 then amount else 0 end) as twelfth,
sum(amount) as total
from mytable
group by year(dateadd(month, - month(#startdate) + 1, d_date))
order by year(dateadd(month, - month(#startdate) + 1, d_date));
And again, if we want our results start from the fiscal year of the given date, we'd add:
where year(dateadd(month, - month(#startdate) + 1, d_date)) >= year(#startdate)

SQL I want to get the following output

I have a sales table
Date_s sales_man product qty
1-Jan-18 xx 01 30
1-Jan-18 xx 01 20
1-Jan-18 xy 01 20
1-Feb-18 xz 02 10
5-Feb-18 xz 02 30
1-Feb-18 xx 01 10
1-Feb-18 xx 01 40
1-Mar-18 xy 03 20
I want to get the following output data format as
Product sales_man Jan Feb Mar
01 xx 50 10 0
01 xy 20 0 0
02 xx 0 0 0
02 xy 0 0 0
02 xz 0 0 0
03 xy 0 0 20
You can use aggregation. Something like this:
select product, salesperson,
sum(case when extract(month from dates) = 1 then qty else 0 end) as jan,
sum(case when extract(month from dates) = 2 then qty else 0 end) as feb
from t
group by product, salesperson;
This uses ANSI SQL date functions, because your database tag is not clear. Date operations can differ by database.
Also, when looking at data by month, typically, you want to take the year into account as well (by filtering or aggregating on the year).
If i got Your problem right, you can try:
SELECT * into #TempTable FROM
(select product, salesman, qty, FORMAT(Dates, 'MMM') as Months from sales
) AS s
PIVOT
(
SUM(qty)
FOR Months in (Jan, Feb)
) AS Pvt
select product, salesman, isnull(Jan, 0) as Jan, isnull(Feb, 0) as Feb from
#TempTable order by product
drop table #TempTable
If you can change your date format from '1-Jan-18' to '1-01-18', then you can do below way
check sql fiddle
http://sqlfiddle.com/#!9/6d3824/2
If you consider below date format
'1-01-18',
'1-01-18',
'1-02-18';
then you can do this query
select product, salesman,
sum(case when extract(month from dates) = 1 then qty else 0 end) as jan,
sum(case when extract(month from dates) = 2 then qty else 0 end) as feb
from sales
group by product, salesman;
Result
product salesman jan feb
1 xx 30 0
1 xz 0 20
2 xy 10 0
For all month
http://sqlfiddle.com/#!9/6d3824/9
for all do query like this,
select product, salesman,
sum(case when extract(month from dates) = 1 then qty else 0 end) as jan,
sum(case when extract(month from dates) = 2 then qty else 0 end) as feb,
sum(case when extract(month from dates) = 3 then qty else 0 end) as mar,
sum(case when extract(month from dates) = 4 then qty else 0 end) as apr,
sum(case when extract(month from dates) = 5 then qty else 0 end) as may,
sum(case when extract(month from dates) = 6 then qty else 0 end) as jun,
sum(case when extract(month from dates) = 7 then qty else 0 end) as jul,
sum(case when extract(month from dates) = 8 then qty else 0 end) as aug,
sum(case when extract(month from dates) = 9 then qty else 0 end) as sep,
sum(case when extract(month from dates) = 10 then qty else 0 end) as oct,
sum(case when extract(month from dates) = 11 then qty else 0 end) as nov,
sum(case when extract(month from dates) = 12 then qty else 0 end) as dece
from sales
group by product, salesman;
Result would be
product salesman jan feb mar apr may jun jul aug sep oct nov dece
1 xx 30 0 0 0 0 0 0 0 0 0 0 0
1 xz 0 20 0 0 0 0 0 0 0 0 0 0
2 xy 10 0 0 0 0 0 0 0 0 0 0 0

Splits one column to multiple column according to data

I have a table which contains data of std attendance of one year
AttID Present absent. leave sick month StdRegNo
1. 23 1 0 0 JAN. 1
2. 25 0 0 0 JAN. 2
3. 23 0 0 0 MAR. 1
4. 21 3 0 1 MAR. 2
SO ON.......
I want result in such a view as bellow:
StdReq month P A L S month P A L S
1. Jan. 23 1 0 0 Mar 23 0 0 0
2. Jan. 25 0 0 0 Mar 21 3 0 1
I need this view for 12 months how can I do this? please help me
You can use a query like this:
select StdRegNo
-- January info
,max(case when [month] = 'JAN' then Present end) JAN_P
,max(case when [month] = 'JAN' then [absent] end) JAN_A
,max(case when [month] = 'JAN' then leave end) JAN_L
,max(case when [month] = 'JAN' then sick end) JAN_S
-- March info
,max(case when [month] = 'MAR' then Present end) MAR_P
,max(case when [month] = 'MAR' then [absent] end) MAR_A
,max(case when [month] = 'MAR' then leave end) MAR_L
,max(case when [month] = 'MAR' then sick end) MAR_S
-- And so on ...
from yourTable
group by StdRegNo;

SQL query to count incidents by year by month

I have one table called Incidents. I want a SQL query that returns the count of incidents split out by year, by month. The start year is 2010, however, the end year will be variable.
Example Incidents table:
DateLogged IncidentRef
----------- ------------
2015-04-05 1
2014-06-04 2
2013-01-01 3
2012-12-10 4
2011-10-15 5
2010-10-01 6
2012-12-11 7
2011-10-10 8
2010-10-10 9
Query Returns:
Year Jan Fev Mar Abr Mai Jun Jul Ago Set Out Nov Dez
2010 0 0 0 0 0 0 0 0 0 2 0 0
2011 0 0 0 0 0 0 0 0 0 2 0 0
2012 0 0 0 0 0 0 0 0 0 0 0 2
2013 1 0 0 0 0 0 0 0 0 0 0 0
2014 0 0 0 0 0 1 0 0 0 0 0 0
2015 0 0 0 1 0 0 0 0 0 0 0 0
How can I do that query? Where do I start?
One option is to use conditional aggregation:
select year(datelogged),
sum(case when month(datelogged) = 1 then 1 else 0 end) Jan,
sum(case when month(datelogged) = 2 then 1 else 0 end) Feb,
...,
sum(case when month(datelogged) = 12 then 1 else 0 end) Dec
from yourtable
group by year(datelogged)
SQL Fiddle Demo
With pivoting:
;with cte as(select year(date) y, month(date) m, ref from table)
select * from cte
pivot(count(ref) for m in([1],[2],...,[12]))p
Another way to do without a pivot you could use a join:
with years as
(
SELECT 2010 as y
UNION ALL
SELECT 2011
UNION ALL
SELECT 2012
UNION ALL
SELECT 2013
UNION ALL
SELECT 2014
UNION ALL
SELECT 2015
)
select years.y,
sum(case when month(DateLogged) = 1 then 1 else 0) as jan,
sum(case when month(DateLogged) = 2 then 1 else 0) as feb,
sum(case when month(DateLogged) = 3 then 1 else 0) as mar,
sum(case when month(DateLogged) = 4 then 1 else 0) as apr,
-- ...
sum(case when month(DateLogged) = 12 then 1 else 0) as dec,
from years y
left join incidents i on y.y = year(i.DateLogged)
group by y.DateLogged
If you want year to be "dynamic" you have the CTE like this
with years as
(
SELECT DISTINCT year(i.DateLogged) FROM incidents
)
but this has the same drawback as the sgeddes solution -- years with no values don't show up.
Using classic PIVOT:
Data:
CREATE TABLE #Incidents(
DateLogged DATE NOT NULL PRIMARY KEY
,IncidentRef INTEGER NOT NULL );
INSERT INTO #Incidents(DateLogged,IncidentRef) VALUES
('2015-04-05',1),('2014-06-04',2),('2013-01-01',3),
('2012-12-10',4),('2011-10-15',5),('2010-10-01',6),
('2012-12-11',7),('2011-10-10',8),('2010-10-10',9);
Query:
;WITH cte AS
(
SELECT [year] = YEAR(DateLogged),
[month] = CASE MONTH(DateLogged)
WHEN 1 THEN 'Jan' WHEN 2 THEN 'Fev'
WHEN 3 THEN 'Mar' WHEN 4 THEN 'Abr'
WHEN 5 THEN 'Mai' WHEN 6 THEN 'Jun'
WHEN 7 THEN 'Jul' WHEN 8 THEN 'Ago'
WHEN 9 THEN 'Set' WHEN 10 THEN 'Out'
WHEN 11 THEN 'Nov' WHEN 12 THEN 'Dez'
END,
IncidentRef
FROM #Incidents
)
SELECT [Year],Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, [Set], Out, Nov, Dez
FROM cte
PIVOT (
COUNT(IncidentRef)
FOR [month] IN (Jan, Fev, Mar, Abr, Mai, Jun,Jul, Ago, [Set], Out, Nov,Dez)
) AS piv;
LiveDemo
SQL Server 2012+
Using CHOOSE added UNION to cte to ensure to get zeros for missing years:
;WITH cte AS
(
SELECT [year] = YEAR(DateLogged),
[month] = CHOOSE(MONTH(DateLogged),'Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'),
IncidentRef
FROM #Incidents
UNION ALL
SELECT [year], NULL, NULL
FROM (VALUES (2010),(2011),(2012),(2013),(2014),(2015)) AS t([year])
)
SELECT [Year],Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, [Set], Out, Nov, Dez
FROM cte
PIVOT (
COUNT(IncidentRef)
FOR [month] IN (Jan, Fev, Mar, Abr, Mai, Jun,Jul, Ago, [Set], Out, Nov,Dez)
) AS piv
ORDER BY [Year];
LiveDemo2

Select changed records

I have what I would have thought was a common problem but I have searched and cannot find an answer.
I have a large table containing (simplified) Month, Project, Type, Value
Jan ProjectA X 15000,
Jan ProjectB X 2000,
Jan ProjectB Y 2000,
Jan ProjectC X 3000,
.....
Feb ProjectA X 15000,
Feb ProjectB Y 4000,
Feb ProjectC X 3000,
Feb ProjectD X 8989,
.....
Mar ProjectA X 15000,
Mar ProjectB Y 4000,
Mar ProjectC X 3000,
Mar ProjectD X 8989,
.....
I need a query which shows:
All projects+type in Jan but not Feb AND
All projects+type in Feb but not Jan AND
All projects+type in both but with different Values
I need it between any two months sorry for not being clear
Any help would be greatly appreciated (I have tried sub queries with NOT IN and joins but I feel that I am missing something simple as my queries became very large and still did not work)
You should be able to do this with aggregation:
select project, type,
(case when sum(case when month = 'jan' then 1 else 0 end) > 0 and
sum(case when month = 'feb' then 1 else 0 end) = 0
then 'Jan-Only'
when sum(case when month = 'jan' then 1 else 0 end) = 0 and
sum(case when month = 'feb' then 1 else 0 end) > 0
then 'Feb-Only'
when max(case when month = 'jan' then value else 0 end) <>
max(case when month = 'feb' then value else 0 end)
then 'Different'
end) as Which
from largetable lt
group by project, type;
Probably the easiest way to filter out the ones where the values are equal in jan and feb is to use a subquery:
select t.*
from (select project, type,
(case when sum(case when month = 'jan' then 1 else 0 end) > 0 and
sum(case when month = 'feb' then 1 else 0 end) = 0
then 'Jan-Only'
when sum(case when month = 'jan' then 1 else 0 end) = 0 and
sum(case when month = 'feb' then 1 else 0 end) > 0
then 'Feb-Only'
when max(case when month = 'jan' then value else 0 end) <>
max(case when month = 'feb' then value else 0 end)
then 'Different'
end) as Which
from largetable lt
where month in ('jan', 'feb')
group by project, type
) t
where Which is not null;