Pivot SQL table - sql

I have a table with a column "date" and "name".
Here you can find a sample of my table: http://sqlfiddle.com/#!2/eddede/1
What I need to do is to count how many rows a person has for every year. If the person doesn't have a value in year X, you must see 0. The order of the names must be on total count of current year DESC, so at the moment: 2014.
I can count for every year/name, but not sure I need this for the pivot table: http://sqlfiddle.com/#!2/eddede/3
I would like that the result should look like this:
NAME 2012 2013 2014 TOTAL
Person B 2 2 2 6
Person C 0 1 2 3
Person A 4 3 1 8
I've tried, but I get something like this (So I don't post the wrong SQL-query...)
2012 2013 2014
6 6 5

You can get the result using an aggregate function with some conditional logic like a CASE expression:
select
name,
sum(case when year(date) = 2012 then 1 else 0 end) [2012],
sum(case when year(date) = 2013 then 1 else 0 end) [2013],
sum(case when year(date) = 2014 then 1 else 0 end) [2014],
count(*) Total
from list
group by name;
See SQL Fiddle with Demo
Now, if the year values are unknown, then you will need to use dynamic SQL. This creates a string of the SQL that you need to execute:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#orderby nvarchar(max)
select #cols
= STUFF((SELECT ',' + QUOTENAME(year(date))
from list
group by year(date)
order by year(date)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #orderby = 'ORDER BY ['+cast(year(getdate()) as varchar(4)) + '] desc'
set #query = 'SELECT name, ' + #cols + ', Total
from
(
select name, year(date) dt,
count(*) over(partition by name) Total
from list
) x
pivot
(
count(dt)
for dt in (' + #cols + ')
) p '+ #orderby
exec sp_executesql #query;
See SQL Fiddle with Demo

I think this is what you are looking for:
SELECT
name,
SUM(if(year(date) = 2012, 1, 0)) AS '2012',
SUM(if(year(date) = 2013, 1, 0)) AS '2013',
SUM(if(year(date) = 2014, 1, 0)) AS '2014'
FROM list
GROUP BY name;
and with total :)
SELECT
t.name,
t.`2012`,
t.`2013`,
t.`2014`,
t.`2012` + t.`2013` + t.`2014` as total
FROM
(
SELECT
name,
SUM(if(year(date) = 2012, 1, 0)) AS `2012`,
SUM(if(year(date) = 2013, 1, 0)) AS `2013`,
SUM(if(year(date) = 2014, 1, 0)) AS `2014`
FROM list
GROUP BY name
) as t

Related

Error during PIVOT in SQL Server 2014

I am trying to create pivot where row is Brand and SKU, sum is qty for column YYMM, but I'm not sure why it is throwing an error. Please help.
Code:
DECLARE #TABLE TABLE
(
SKU VARCHAR(10),
YYMM VARCHAR(50),
BRAND VARCHAR(50),
QTY INT
)
INSERT INTO #TABLE
SELECT '104591168', '2015-January', 'abott', 2 UNION ALL
SELECT '104580709', '2016-January', 'GSK', 2 UNION ALL
SELECT '104720038', '2017-January', 'RANBAXCY', 2 UNION ALL
SELECT '10467011A', '2018-January', 'abott', 2 UNION ALL
SELECT '104590691', '2019-January', 'abott', 10
Pivot code:
select *
from
(select
BRAND, sku, QTY, YYMM
from #TABLE) src
pivot
(sum(QTY)
for [Year Month]
You forgot to finish your query.
Please see the bottom of MSDN article for PIVOT examples.
I would guess that you wanted your query to look something like this:
SELECT *
FROM(
SELECT BRAND, sku, QTY, YYMM
FROM #TABLE
) AS src
PIVOT(
sum(QTY)
for [YYMM] IN( [2015-January], [2016-January], [2017-January] /* add other moneths here */ )
) AS Pivoted
We can make it as Dynamic sql
DECLARE #Column NVARCHAR(max),
#Column2 NVARCHAR(max),
#Sql NVARCHAR(max)
SELECT #Column = Stuff((SELECT DISTINCT ', '
+ Quotename(Cast(yymm AS VARCHAR(20)))
FROM #table
FOR xml path ('')), 1, 1, '')
SELECT #Column2 = Stuff((SELECT DISTINCT ', ' + 'ISNULL('
+ Quotename(Cast(yymm AS VARCHAR(20)))
+ ','
+ '''0''' + ') AS '
+ Quotename(Cast(yymm AS VARCHAR(20)))
FROM #table
FOR xml path ('')), 1, 1, '')
SET #Sql='
SELECT BRAND ,sku,'+#Column2+'
FROM(
SELECT *
FROM #TABLE
) AS src
PIVOT(
sum(QTY)
for [YYMM] IN('+#Column+')
) AS Pivoted
'
PRINT #Sql
EXEC(#Sql)
Result
BRAND sku 2015-January 2016-January 2017-January 2018-January 2019-January
--------------------------------------------------------------------------------------------------------
abott 104590691 0 0 0 0 10
abott 104591168 2 0 0 0 0
abott 10467011A 0 0 0 2 0
GSK 104580709 0 2 0 0 0
RANBAXCY 104720038 0 0 2 0 0

creating a pivot table using sql

I am trying to create a pivot table in sql but am having difficulties. Here is my problem: I have a column in my database called 'statusreason', and I need to provide a sum of each statusreason for the past week. My set is as follows:
I need to pivot this table so that it appears like the following:
There are a number of statusreasons that are not represented in the above table, since they did not occur in the past week.
The query used to generate the result set is:
select inv.statusreason
, count(inv.statusreason) as 'StatusCount'
from invoicetbl inv (nolock)
inner join trucktbl tru (nolock) on inv.tru_key = tru.tru_key
where inv.client_key = 123
and inv.createdate > getdate() - 7
group by inv.statusreason
If this isn't enough information, please advise what I could add to improve the question.
Thank you for any assistance you can provide.
Since you want to convert your rows of data into columns, you need to PIVOT the data. This can be done a number of ways.
If you have a limited number of values that you are going to be returning, then you can use an aggregate function with a CASE expression:
select
count(case when statusreason = 181 then 1 end) [181],
count(case when statusreason = 20 then 1 end) [20],
count(case when statusreason = 212 then 1 end) [212],
count(case when statusreason = 232 then 1 end) [232]
from
(
select inv.statusreason
from invoicetbl inv (nolock)
inner join trucktbl tru (nolock)
on inv.tru_key = tru.tru_key
where inv.client_key = 123
and inv.createdate > getdate() - 7
) d;
Or you can use the PIVOT function:
select [181], [20], [212], [232]
from
(
select inv.statusreason
from invoicetbl inv (nolock)
inner join trucktbl tru (nolock)
on inv.tru_key = tru.tru_key
where inv.client_key = 123
and inv.createdate > getdate() - 7
) d
pivot
(
count(statusreason)
for statusreason in ([181], [20], [212], [232])
) p;
If you have an unknown number of values that will be returned, then you will want to look at using dynamic SQL. This creates a sql string that will then be executed.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(statusreasons )
from statusreasontbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ' + #cols + '
from
(
select inv.statusreason
from invoicetbl inv (nolock)
inner join trucktbl tru (nolock)
on inv.tru_key = tru.tru_key
where inv.client_key = 123
and inv.createdate > getdate() - 7
) x
pivot
(
count(statusreason)
for statusreason in (' + #cols + ')
) p '
execute sp_executesql #query;

sql query to dynamically add fiscal month using pivot

ALTER PROCEDURE [dbo].[_sp_GetDMActivityTrackerReport]
#CoachId VARCHAR(7),
#Month INT,
#FiscalYear INT
AS
BEGIN
INSERT #FiscalMonth (ID,Month,NbHolidays,MonthDate,TotalDays)
EXECUTE dbo._sp_GetFiscalMonths #Month, #FiscalYear
SELECT PreparationID,CoachId,UserID, MemberID,
[Rep Name], isnull(April,0) April, isnull(May,0) May, isnull(June,0)June,
isnull(July,0) July, isnull(August,0) August, isnull(September,0) September,
isnull(October,0) October, isnull(November,0) November,
isnull(December,0) December, isnull(January,0) January, isnull(February,0) February,
isnull(March,0) March,isnull((isnull(November,0) + isnull(December,0) +
isnull(January,0) + isnull(February,0) + isnull(March,0) + isnull(April,0) +
isnull(May,0) + isnull(June,0) + isnull(July,0) + isnull(August,0) +
isnull(September,0) + isnull(October,0)),0) as [Total Field TIME]
FROM
(
SELECT up.PreparationID,tt.UserId [CoachId],up.UserID, utm.MemberID,
(ui.FirstName + ' ' + ui.LastName) AS [Rep Name],DateName(Month,nft.MonthPeriodStart) [Month], sum(nft.Quantity) [Days]
FROM TransferedTime tt
INNER JOIN UPreparation up ON tt.PreparationID = up.PreparationID
RIGHT JOIN UTeamMembers utm ON tt.UserId = utm.CoachID AND utm.MemberID = up.UserID
INNER JOIN UserInfo ui ON utm.MemberID = ui.UserID
LEFT JOIN NonFieldTime nft ON nft.UserId = tt.UserId
AND tt.MonthPeriodFrom = nft.MonthPeriodStart
AND datename(Month,nft.MonthPeriodStart) + '-'+ substring(datename(Year,nft.MonthPeriodStart),3,2) IN
(SELECT Month +'-' +substring(datename(Year,MonthDate),3,2) [Months] FROM #FiscalMonth)
WHERE utm.MemberID IN (SELECT MemberID FROM UTeamMembers WHERE CoachID = #CoachId)
GROUP BY up.PreparationID,tt.UserId,up.UserID, utm.MemberID,
(ui.FirstName + ' ' + ui.LastName),DateName(Month,nft.MonthPeriodStart)) src
pivot
(
sum(Days)
for Month in (April, May, June, July, August, September, October,November, December, January, February, March)
)
piv
#Fiscalmonth returns:
Id, Month, NbHolidays, MonthDate
1 April 1 4/1/2012
2 May 2 5/1/2012
3 June 3 6/1/2012
4 July 4 7/1/2012
5 August 5 8/1/2012
6 September 6 9/1/2012
7 October 7 10/1/2012
8 November 8 11/1/2012
9 December 9 12/1/2012
10 January 10 1/1/2013
11 February 11 2/1/2013
12 March 12 3/1/2013
I have a stored procedure which generate report according to the fiscal year.
here fiscal year and fiscal month comes from the database now I am facing problem in generating this report dynamically as you can see i had fixed the months year which is not a good practice i want it to some way that if i changed the fiscal month in the database then my report reflect accordingly.
You will need to use dynamic SQL to do this. The rough code is going to be similar to this:
ALTER PROCEDURE [dbo].[_sp_GetDMActivityTrackerReport]
#CoachId VARCHAR(7),
#Month INT,
#FiscalYear INT
AS
BEGIN
INSERT #FiscalMonth (ID,Month,NbHolidays,MonthDate,TotalDays)
EXECUTE dbo._sp_GetFiscalMonths #Month, #FiscalYear
DECLARE #cols AS NVARCHAR(MAX),
#colsNull AS NVARCHAR(MAX),
#colsSum AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(DateName(Month,nft.MonthPeriodStart))
from NonFieldTime nft
where datename(Month,nft.MonthPeriodStart) + '-'+ substring(datename(Year,nft.MonthPeriodStart),3,2)
IN (SELECT Month +'-' +substring(datename(Year,MonthDate),3,2) [Months]
FROM +#FiscalMonth)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
select #colsNull = STUFF((SELECT distinct ', IsNull(' + QUOTENAME(DateName(Month,nft.MonthPeriodStart))+', 0) as '+DateName(Month,nft.MonthPeriodStart)
from NonFieldTime nft
where datename(Month,nft.MonthPeriodStart) + '-'+ substring(datename(Year,nft.MonthPeriodStart),3,2)
IN (SELECT Month +'-' +substring(datename(Year,MonthDate),3,2) [Months]
FROM +#FiscalMonth)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
select #colsSum = STUFF((SELECT distinct '+ IsNull(' + QUOTENAME(DateName(Month,nft.MonthPeriodStart))+', 0)'
from NonFieldTime nft
where datename(Month,nft.MonthPeriodStart) + '-'+ substring(datename(Year,nft.MonthPeriodStart),3,2)
IN (SELECT Month +'-' +substring(datename(Year,MonthDate),3,2) [Months]
FROM +#FiscalMonth)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')+' as [Total Field TIME] '
set #query = 'SELECT PreparationID,CoachId,UserID, MemberID,
[Rep Name], ' + #colsNull + ', '+ #colsSum+'
from
(
SELECT up.PreparationID,
tt.UserId [CoachId],
up.UserID, utm.MemberID,
(ui.FirstName + '' '' + ui.LastName) AS [Rep Name],
DateName(Month,nft.MonthPeriodStart) [Month],
sum(nft.Quantity) [Days]
FROM TransferedTime tt
INNER JOIN UPreparation up
ON tt.PreparationID = up.PreparationID
RIGHT JOIN UTeamMembers utm
ON tt.UserId = utm.CoachID AND utm.MemberID = up.UserID
INNER JOIN UserInfo ui
ON utm.MemberID = ui.UserID
LEFT JOIN NonFieldTime nft
ON nft.UserId = tt.UserId
AND tt.MonthPeriodFrom = nft.MonthPeriodStart
AND datename(Month,nft.MonthPeriodStart) + ''-''+ substring(datename(Year,nft.MonthPeriodStart),3,2) IN
(SELECT Month +''-'' +substring(datename(Year,MonthDate),3,2) [Months]
FROM +#FiscalMonth)
WHERE utm.MemberID IN (SELECT MemberID
FROM UTeamMembers
WHERE CoachID = '+#CoachId+')
GROUP BY up.PreparationID,tt.UserId,up.UserID, utm.MemberID,
(ui.FirstName + '' '' + ui.LastName),DateName(Month,nft.MonthPeriodStart)
) x
pivot
(
sum(Days)
for Month in (' + #cols + ')
) p '
execute(#query)
My suggestion instead of using the temp table #FiscalMonth is to create a table that is permanent for this. It will be much simpler to query against a perm table rather than the temp table when using dynamic sql. The temp table might be out of scope for the dynamic query.
There is PIVOT XML option in Oracle that allows you to avoid hard coding. I'm not sure if there is such option in SQL Server. You can write smth lk this - also Oracle query:
SELECT count(decode(state,'FL',custid)) "FL"
, count(decode(state,'NY',custid)) "NY"
, count(decode(state,'CA',custid)) "CA"
FROM scott.customer
GROUP BY state
/
Replace state with month etc...
Output:
FL NY CA
--- --- ---
0 2 0
5 0 8
Oracle example:
http://www.oracle-base.com/articles/11g/pivot-and-unpivot-operators-11gr1.php
SELECT * FROM
(
SELECT product_code, quantity
FROM pivot_test
)
PIVOT XML
(
SUM(quantity) AS sum_quantity
FOR (product_code) IN (SELECT DISTINCT product_code
FROM pivot_test
WHERE id < 10)
)
/

rows to columns partly

Could anybody guide me how to pivot my data. I have:
RowID Dimension Value
1 Country Italy
1 Year 2011
1 GDP 4
1 Population 6
2 Country Spain
2 Year 2011
2 GDP 7
2 Population 5
I want in a such way:
RowID Country Year GDP Population
1 Italy 2011 4 6
2 Spain 2011 7 5
P.S. I use MS SQL Server 2008 R2 Express Edition. I tried to use PIVOT but it returned many rows with NULL so I could not figure out.
You can use PIVOT for this. This can be hard-coded if you know all of the values:
select *
from
(
select rowid, dimension, value
from yourtable
) src
pivot
(
max(value)
for dimension in ([Country], [Year], [GDP], [Population])
) piv
See SQL Fiddle with Demo
Or of you do not have access to the PIVOT function, then you can use an aggregate with a CASE:
select rowid,
max(case when dimension = 'country' then value end) country,
max(case when dimension = 'Year' then value end) Year,
max(case when dimension = 'GDP' then value end) GDP,
max(case when dimension = 'Population' then value end) Population
from yourtable
group by rowid
See SQL Fiddle with Demo
If you have an unknown number of values, then you can use dynamic sql:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Dimension)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT rowid, ' + #cols + ' from
(
select rowid, dimension, value
from yourtable
) x
pivot
(
max(value)
for dimension in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo

Convert Rows to columns using 'Pivot' in mssql when columns are string data type

I need to know whether 'pivot' in MS SQL can be used for converting rows to columns if there is no aggregate function to be used. i saw lot of examples with aggregate function only. my fields are string data type and i need to convert this row data to column data.This is why i wrote this question.i just did it with 'case'. Can anyone help me......Thanks in advance.
You can use a PIVOT to perform this operation. When doing the PIVOT you can do it one of two ways, with a Static Pivot that you will code the rows to transform or a Dynamic Pivot which will create the list of columns at run-time:
Static Pivot (see SQL Fiddle with a Demo):
SELECT *
FROM
(
select empid, wagecode, amount
from t1
) x
pivot
(
sum(amount)
for wagecode in ([basic], [TA], [DA])
) p
Dynamic Pivot:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(wagecode)
FROM t1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT empid, ' + #cols + ' from
(
select empid, wagecode, amount
from t1
) x
pivot
(
sum(amount)
for wagecode in (' + #cols + ')
) p '
execute(#query)
Both of these will give you the same results
sample format
empid wagecode amount
1 basic 1000
1 TA 500
1 DA 500
2 Basic 1500
2 TA 750
2 DA 750
empid basic TA DA
1 1000 500 500
2 1500 750 750
THE ANSWER I GOT IS
SELECT empID , [1bas] as basic, [1tasal] as TA,[1otsal] as DA
FROM (
SELECT empID, wage, amount
FROM table) up
PIVOT (SUM(amt) FOR wgcod IN ([1bas], [1tasal],[1otsal])) AS pvt
ORDER BY empID
GO
Try this:
SELECT empid AS EmpID
, ISNULL(SUM(CASE wagecode WHEN 'basic' THEN Amount ELSE 0 END), 0) AS Basic
, ISNULL(SUM(CASE wagecode WHEN 'ta' THEN Amount ELSE 0 END), 0) AS TA
, ISNULL(SUM(CASE wagecode WHEN 'da' THEN Amount ELSE 0 END), 0) AS DA
FROM Employee
GROUP BY empid