how can I use Pivot using a variable in SQL? - sql

I have paycode numbers and Names from table Paycodes
and I have Amount in monthlyTransaction. as follows:
Paycodes
Code Name
1 Basic Salary
2 Variable Deduction Amount
3 Fixed/Var Insurance PayCode
MonthlyTransaction
Code Amount
1 3000
2 10000
1 130000
1 150000
3 120000
I want it to be like this using pivot
Basic Salary Variable Deduction Amount Fixed/Var Insurance PayCode
31000 10000 120000
I want to use pivot to sum the Amount of each Paycode and I used this:-
DECLARE #data AS NVARCHAR(MAX)
DECLARE #query AS NVARCHAR(MAX)
-- DECLARE #data TABLE
--(
-- PaycodeName NVARCHAR(max)
--)
--INSERT INTO #data
-- ( PaycodeName )
--select dbo.Paycode.PayCodeName FROM dbo.Paycode
select #data = Paycode.PayCodeName FROM Paycode
set #query = 'SELECT * FROM (
SELECT Paycode.Name , MonthlyTransaction.Amount
From MonthlyTransaction
LEFT JOIN dbo.Paycode ON Paycode.code = MonthlyTransaction.Paycode
) AS s
PIVOT
(
SUM(Amount)
FOR Paycode.Name IN ('+#data+')
) AS pvt '
EXECUTE Sp_executesql #query
When I print #data it retrieve the last paycode only !
Can anyone help ?

To get all the paycodes in #data use
SELECT #data = #data + Paycode.PayCodeName + ', '
FROM Paycode
Then remove the last comma

the answer is :
DECLARE #codeNameCol NVARCHAR(max)
SELECT #codeNameCol= COALESCE(#codeNameCol + ',','') + QUOTENAME(RTRIM(LTRIM(PayCodeName)))
FROM (SELECT DISTINCT PayCodeName FROM Paycode) AS codeNameCol
DECLARE #querys NVARCHAR(max)
Set #querys='
SELECT *
FROM ( SELECT dbo.EmpAssignment.EmployeeId ,
PayCodeName ,
Amount
FROM dbo.MonthlyTransaction
LEFT JOIN dbo.Paycode ON Paycode.code = MonthlyTransaction.Paycode
LEFT JOIN dbo.EmpAssignment ON EmpAssignment.EmpId = MonthlyTransaction.EmpId
LEFT JOIN dbo.PayrollGroup ON PayrollGroup.PayrollGroup = EmpAssignment.PayrollGroup
) DataTable PIVOT
( SUM(Amount) FOR PayCodeName IN ( '+#codeNameCol+' ) ) PivotTable;'
EXEC (#querys)

This should do the trick
SELECT 1 Code, 'Basic Salary' Name
INTO #Paycode
UNION
SELECT 2 Code, 'Variable Deduction Amount' Name
UNION
SELECT 3 Code, 'Fixed/Var Insurance PayCode' Name
SELECT 1 Code, 3000 Amount
INTO #MonthTrans
UNION
SELECT 2 Code, 10000 Amount
UNION
SELECT 1 Code, 130000 Amount
UNION
SELECT 1 Code, 150000 Amount
UNION
SELECT 3 Code, 120000 Amount
DECLARE #data AS NVARCHAR(MAX)
SELECT #data = ISNULL(#data,'') + '[' +CAST(Code AS varchar) + '], '
FROM #Paycode
SELECT #data=SUBSTRING(#data, 0, LEN(#data))
DECLARE #query AS NVARCHAR(MAX)
SELECT #query = 'SELECT *
FROM
#MonthTrans M
PIVOT (
SUM(Amount) FOR Code IN (' + #data + ')
) pvt'
EXECUTE Sp_executesql #query
drop table #paycode
drop table #MonthTrans

Related

Dynamically create table columns with values from Pivot Table

I have a dynamic query that utilizes a pivot function and the following is an example of data in my table.
Status 1 | Week 1 |25
Status 1 | Week 1 |25
Status 1 | Week 2 |25
Status 2 | Week 1 | 2
Status 2 | Week 1 | 8
Status 2 | Week 1 | 10
Status 2 | Week 1 | 10
and this is an example of how the data is returned.
Week 1 Week 2
Status 1 | 50 25
Status 2 10 20
For my query I am passing in a week and I want to pivot on the following 5 weeks, so example, if I pass in 1, I expect to have columns from week 1 to week 6.
To help facilitate that I have written the following query.
--EXEC usp_weekReport #weeks=1, #year='2019'
ALTER PROC usp_weekReport
(
#weeks INT,
#year NVARCHAR(4)
)
AS
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX), #csql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', p.' + QUOTENAME([week])
FROM (
SELECT p.[week]
FROM [Housing_support_DB].[dbo].[Invoices] P
WHERE DATEPART(YEAR,P.date)='2019'--#year
AND
([week] IN (1)
OR
[week] IN (1+1)
OR
[week] IN (1+2)
OR
[week] IN (1+3)
OR
[week] IN (1+4)
OR
[week] IN (1+5)
)
GROUP BY P.[week]
) AS x;
SET #sql = N'
SELECT p.[statusName],' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT
SUM(CAST(REPLACE(REPLACE(A.amount,'','',''''),''$'','''') AS FLOAT)) as sumInvoice,
A.invoiceStatusID_FK,
B.statusName,
-- C.programme,
[week]
FROM [dbo].[Invoices] A
INNER JOIN invoiceStatus B
ON A.invoiceStatusID_FK=B.invoiceStatusID
-- INNER JOIN CapitalAccountBalances C
-- ON C.accountBalanceID=A.accountBalanceID_FK
-- WHERE A.accountBalanceID_FK=5
GROUP BY invoiceStatusID_FK,B.statusName,[week]--,C.programme
) AS j
PIVOT
(
SUM(sumInvoice) FOR [week] IN ('
+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '')
+ ')
) AS p;';
--PRINT #sql;
EXEC sp_executesql #sql;
--SET #csql = N'
--CREATE TABLE ##reportResult
--(
--statusName nvarchar(50),'+
CREATE TABLE ##reportResult
(
statusName nvarchar(50),
weekA INT DEFAULT 0,
weekB int DEFAULT 0--,
--weekC int DEFAULT 0,
--weekD int DEFAULT 0,
--weekE int DEFAULT 0,
--weekF int DEFAULT 0
)
INSERT into ##reportResult Exec(#sql)
--INSERT ##reportResult Exec(#sql)
--SELECT statusName, weekA,weekB,weekC,weekD,weekE,weekF -- here you have "static SELECT with field names"
--FROM ##reportResult
--DROP TABLE ##reportResult
Problem
The huge problem that I have here is that, I need to send the result of this query to a tempTable...#reportResult. As a result, I need to create the table. However, if I attempt to create the table with the max amount of columns anticipated (6) I will get an invalid number of columns error. For example, in my database I only have two weeks, that's why I can only create the table with columns weekA and weekB. I also cannot do a select into.
Presently, I am trying to find a way to either create the table dynamically depending on the amount of weeks from the first part of the pivot table. Or, to manipulate the first part of the pivot to select week,week+1 etc as columns when run so that way , I can create the column with all fields.
Appreciate any help that could be provided.
You required dynamic SQL in your case as the column name is need to generate based on th Input week number. Below I have give you the script I created with your sample data using CTE. You just need to updated the script based on your table and requirement.
You can test the code changing the value of Week_No
For your final query, just use the SELECT part after removing the CTE code
DECLARE #Week_No INT = 2
DECLARE #Loop_Count INT = 1
DECLARE #Column_List VARCHAR(MAX) = '[Week '+CAST(#Week_No AS VARCHAR) +']'
WHILE #Loop_Count < 5
BEGIN
SET #Column_List = #Column_List +',[Week '+CAST(#Week_No+#Loop_Count AS VARCHAR) +']'
SET #Loop_Count = #Loop_Count + 1
END
--SELECT #Column_List
EXEC
('
WITH your_table(Status,Week_No,Val)
AS
(
SELECT ''Status 1'',''Week 1'',25 UNION ALL
SELECT ''Status 1'',''Week 1'',25 UNION ALL
SELECT ''Status 1'',''Week 2'',25 UNION ALL
SELECT ''Status 2'',''Week 1'',2 UNION ALL
SELECT ''Status 2'',''Week 1'',8 UNION ALL
SELECT ''Status 2'',''Week 1'',10 UNION ALL
SELECT ''Status 2'',''Week 1'',10
)
SELECT * FROM
(
SELECT * FROM your_table
) AS P
PIVOT
(
SUM(val)
FOR Week_No IN ('+#Column_List+')
)PVT
')

SQL query to get customers yearly net amount and Year to Year growth percentage

Here is the scenario,
I am creating a report where, for each customer yearly ordered amount will be shown. And than the growth percentage comparing the previous years.
What I have tried so far :
SELECT * FROM (select MrCode MrCode17,MrName MrName17, SUM(NetAmt) NetAmount17,SUM(TotalNetAmt) TotalNetAmount17 from TASKORDER_REGISTER where UCODE = 'SR01'
AND TaskOrder_Dt between '2017-1-1 00:00:00' and '2017-12-31 00:00:00'
GROUP BY MrCode,MrName) as abc
FULL JOIN
(select MrCode MrCode16,MrName MrName16, SUM(NetAmt) NetAmount16,SUM(TotalNetAmt) TotalNetAmount16 from TASKORDER_REGISTER where UCODE = 'SR01'
AND TaskOrder_Dt between '2016-1-1 00:00:00' and '2016-12-31 00:00:00'
GROUP BY MrCode,MrName) AS bbb
ON abc.MrCode17 = bbb.MrCode16
FULL JOIN
(select MrCode MrCode15,MrName MrName15, SUM(NetAmt) NetAmount15,SUM(TotalNetAmt) TotalNetAmount15 from TASKORDER_REGISTER where UCODE = 'SR01'
AND TaskOrder_Dt between '2015-1-1 00:00:00' and '2015-12-31 00:00:00'
GROUP BY MrCode,MrName) AS ccc
ON bbb.MrCode16 = ccc.MrCode15
What is the result :
I am not sure what is the best procedure to accmplish the task. There must sume better queries to get data. And I could not create the growth percentage yet.
Please use following query it will return Year,Difference and [Difference Precantage].
Please add other columns in result set
IF OBJECT_ID('tempdb..#SalesData') IS NOT NULL BEGIN DROP TABLE #SalesData END
IF OBJECT_ID('tempdb..#FinalData') IS NOT NULL BEGIN DROP TABLE #FinalData END
SELECT IDENTITY(int, 1,1) AS ID_Num ,year(TaskOrder_Dt) SalesYear,SUM(NetAmt) TotalAmount
INTO #SalesData
FROM TASKORDER_REGISTER GROUP BY year(TaskOrder_Dt)
SELECT
[current].ID_Num,
[current].TotalAmount,
[current].SalesYear,
[current].TotalAmount - ISNULL([next].TotalAmount, 0) AS Diff,
(([current].TotalAmount - ISNULL([next].TotalAmount,0)) * ISNULL([next].TotalAmount,1)) * 100 AS Diffper
INTO #FinalData
FROM #SalesData AS [current]
LEFT JOIN #SalesData AS [next]
ON [next].ID_Num = (SELECT MAX(ID_Num) FROM #SalesData WHERE ID_Num < [current].ID_Num)
DECLARE #cols AS NVARCHAR(MAX),#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(SalesYear) FROM #FinalData FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'),1,1,'')
SELECT #query = 'SELECT * FROM (SELECT [SalesYear],Diff,Diffper FROM #FinalData) X
PIVOT (AVG(Diff) for [SalesYear] in (' + #cols + ')) P'
EXEC SP_EXECUTESQL #query

Group Columns based on Row ID

I have a table pulling data, like:
ID FID Value
001 20 200
001 20 400
001 50 600
002 50 100
How do write a query to get a column for each row ID that would sum the Value's?
For example, I want to return the following:
ID 20 50
001 600 600
002 NULL 100
A pattern like this:
SELECT
ID,
SUM(CASE WHEN FID = 20 THEN Value END) as sum20,
SUM(CASE WHEN FID = 50 THEN Value END) as sum50 --extend by adding more CASE WHEN rows
FROM
table
GROUP BY ID
..has the advantage of working in databases that don't support PIVOT syntax.
If you'd like PIVOT syntax:
SELECT ID, [20], [50] --extend by providing more values in square brackets
FROM
table
PIVOT
(
SUM(Value)
FOR FID IN ([20], [50]) --extend by providing more values in square brackets
) pvt
If you have dynamic list of FID's you can use dynamic query as below:
Declare #cols1 varchar(max)
Declare #query nvarchar(max)
Select #cols1 = stuff((select Distinct ','+QuoteName(Fid) from #data for xml path('')),1,1,'')
Set #query = ' Select * from (
Select Id, [Fid], [Value] from #data ) a
pivot (sum([Value]) for [Fid] in (' + #cols1 + ') ) p '
Exec sp_executesql #query

Dynamic SELECT statement, generate columns based on present and future values

Currently building a SELECT statement in SQL Server 2008 but would like to make this SELECT statement dynamic, so the columns can be defined based on values in a table. I heard about pivot table and cursors, but seems kind of hard to understand at my current level, here is the code;
DECLARE #date DATE = null
IF #date is null
set # date = GETDATE() as DATE
SELECT
Name,
value1,
value2,
value3,
value4
FROM ref_Table a
FULL OUTER JOIN (
SELECT
PK_ID ID,
sum(case when FK_ContainerType_ID = 1 then 1 else null) Box,
sum(case when FK_ContainerType_ID = 2 then 1 else null) Pallet,
sum(case when FK_ContainerType_ID = 3 then 1 else null) Bag,
sum(case when FK_ContainerType_ID = 4 then 1 else null) Drum
from
Packages
WHERE
#date between PackageStart AND PackageEnd
group by PK_ID ) b on a.Name = b.ID
where
Group = 0
The following works great for me , but PK_Type_ID and the name of the column(PackageNameX,..) are hard coded, I need to be dynamic and it can build itself based on present or futures values in the Package table.
Any help or guidance on the right direction would be greatly appreciated...,
As requested
ref_Table (PK_ID, Name)
1, John
2, Mary
3, Albert
4, Jane
Packages (PK_ID, FK_ref_Table_ID, FK_ContainerType_ID, PackageStartDate, PackageEndDate)
1 , 1, 4, 1JAN2014, 30JAN2014
2 , 2, 3, 1JAN2014, 30JAN2014
3 , 3, 2, 1JAN2014, 30JAN2014
4 , 4, 1, 1JAN2014, 30JAN2014
ContainerType (PK_ID, Type)
1, Box
2, Pallet
3, Bag
4, Drum
and the result should look like this;
Name Box Pallet Bag Drum
---------------------------------------
John 1
Mary 1
Albert 1
Jane 1
The following code like I said works great, the issue is the Container table is going to grow and I need to replicated the same report without hard coding the columns.
What you need to build is called a dynamic pivot. There are plenty of good references on Stack if you search out that term.
Here is a solution to your scenario:
IF OBJECT_ID('tempdb..##ref_Table') IS NOT NULL
DROP TABLE ##ref_Table
IF OBJECT_ID('tempdb..##Packages') IS NOT NULL
DROP TABLE ##Packages
IF OBJECT_ID('tempdb..##ContainerType') IS NOT NULL
DROP TABLE ##ContainerType
SET NOCOUNT ON
CREATE TABLE ##ref_Table (PK_ID INT, NAME NVARCHAR(50))
CREATE TABLE ##Packages (PK_ID INT, FK_ref_Table_ID INT, FK_ContainerType_ID INT, PackageStartDate DATE, PackageEndDate DATE)
CREATE TABLE ##ContainerType (PK_ID INT, [Type] NVARCHAR(50))
INSERT INTO ##ref_Table (PK_ID,NAME)
SELECT 1,'John' UNION
SELECT 2,'Mary' UNION
SELECT 3,'Albert' UNION
SELECT 4,'Jane'
INSERT INTO ##Packages (PK_ID, FK_ref_Table_ID, FK_ContainerType_ID, PackageStartDate, PackageEndDate)
SELECT 1,1,4,'2014-01-01','2014-01-30' UNION
SELECT 2,2,3,'2014-01-01','2014-01-30' UNION
SELECT 3,3,2,'2014-01-01','2014-01-30' UNION
SELECT 4,4,1,'2014-01-01','2014-01-30'
INSERT INTO ##ContainerType (PK_ID, [Type])
SELECT 1,'Box' UNION
SELECT 2,'Pallet' UNION
SELECT 3,'Bag' UNION
SELECT 4,'Drum'
DECLARE #DATE DATE, #PARAMDEF NVARCHAR(MAX), #COLS NVARCHAR(MAX), #SQL NVARCHAR(MAX)
SET #DATE = '2014-01-15'
SET #COLS = STUFF((SELECT DISTINCT ',' + QUOTENAME(T.[Type])
FROM ##ContainerType T
FOR XML PATH, TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET #SQL = 'SELECT [Name], ' + #COLS + '
FROM (SELECT [Name], [Type], 1 AS Value
FROM ##ref_Table R
JOIN ##Packages P ON R.PK_ID = P.FK_ref_Table_ID
JOIN ##ContainerType T ON P.FK_ContainerType_ID = T.PK_ID
WHERE #DATE BETWEEN P.PackageStartDate AND P.PackageEndDate) X
PIVOT (COUNT(Value) FOR [Type] IN (' + #COLS + ')) P
'
PRINT #COLS
PRINT #SQL
SET #PARAMDEF = '#DATE DATE'
EXEC SP_EXECUTESQL #SQL, #PARAMDEF, #DATE=#DATE
Output:
Name Bag Box Drum Pallet
Albert 0 0 0 1
Jane 0 1 0 0
John 0 0 1 0
Mary 1 0 0 0
Static Query:
SELECT [Name],[Box],[Pallet],[Bag],[Drum] FROM
(
SELECT *
FROM
(
SELECT rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
) AS SourceTable
PIVOT
(
COUNT(PKID )
FOR [Type]
IN ( [Box],[Pallet],[Bag],[Drum])
) AS PivotTable
) AS Main
ORDER BY RFID
Dynamic Query:
DECLARE #columnList nvarchar (MAX)
DECLARE #pivotsql nvarchar (MAX)
SELECT #columnList = STUFF(
(
SELECT ',' + '[' + [Type] + ']'
FROM ContanerType
FOR XML PATH( '')
)
,1, 1,'' )
SET #pivotsql =
N'SELECT [Name],' + #columnList + ' FROM
(
SELECT *
FROM
(
SELECT rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
) AS SourceTable
PIVOT
(
COUNT(PKID )
FOR [Type]
IN ( ' + #columnList + ')
) AS PivotTable
) AS Main
ORDER BY RFID;'
EXEC sp_executesql #pivotsql
Following my tutorial below will help you to understand the PIVOT functionality:
We write sql queries in order to get different result sets like full, partial, calculated, grouped, sorted etc from the database tables. However sometimes we have requirements that we have to rotate our tables. Sounds confusing?
Let's keep it simple and consider the following two screen grabs.
SQL Table:
Expected Results:
Wow, that's look like a lot of work! That is a combination of tricky sql, temporary tables, loops, aggregation......, blah blah blah
Don't worry let's keep it simple, stupid(KISS).
MS SQL Server 2005 and above has a function called PIVOT. It s very simple to use and powerful. With the help of this function we will be able to rotate sql tables and result sets.
Simple steps to make it happen:
Identify all the columns those will be part of the desired result set.
Find the column on which we will apply aggregation(sum,ave,max,min etc)
Identify the column which values will be the column header.
Specify the column values mentioned in step3 with comma separated and surrounded by square brackets.
So, if we now follow above four steps and extract information from the above sales table, it will be as below:
Year, Month, SalesAmount
SalesAmount
Month
[Jan],[Feb] ,[Mar] .... etc
We are nearly there if all the above steps made sense to you so far.
Now we have all the information we need. All we have to do now is to fill the below template with required information.
Template:
Our SQL query should look like below:
SELECT *
FROM
(
SELECT SalesYear, SalesMonth,Amount
FROM Sales
) AS SourceTable
PIVOT
(
SUM(Amount )
FOR SalesMonth
IN ( [Jan],[Feb] ,[Mar],
[Apr],[May],[Jun] ,[Jul],
[Aug],[Sep] ,[Oct],[Nov] ,[Dec])
) AS PivotTable;
In the above query we have hard coded the column names. Well it's not fun when you have to specify a number of columns.
However, there is a work arround as follows:
DECLARE #columnList nvarchar (MAX)
DECLARE #pivotsql nvarchar (MAX)
SELECT #columnList = STUFF(
(
SELECT ',' + '[' + SalesMonth + ']'
FROM Sales
GROUP BY SalesMonth
FOR XML PATH( '')
)
,1, 1,'' )
SET #pivotsql =
N'SELECT *
FROM
(
SELECT SalesYear, SalesMonth,Amount
FROM Sales
) AS SourceTable
PIVOT
(
SUM(Amount )
FOR SalesMonth
IN ( ' + #columnList +' )
) AS PivotTable;'
EXEC sp_executesql #pivotsql
Hopefully this tutorial will be a help to someone somewhere.
Enjoy coding.

transpose rows to columns in sql

I have problem in getting the desired output with the SQL query.
My sql data is as follows:
TOTAL Charge PAYMNET A B C D E MonthYear
------- ----------- ----------- --------- -------- ---------- ------- ------- ----------
661 157832.24 82967.80 700.00 10.70 58329.33 0.00 0.00 Oct-2013
612 95030.52 17824.28 850.00 66.10 53971.41 0.00 0.00 Nov-2013
584 90256.35 16732.91 700.00 66.10 52219.87 0.00 0.00 Dec-2013
511 72217.32 12336.12 285.00 53.17 42951.12 0.00 0.00 Jan-2014
I need the output as follows,
Data Jan-2013 Feb-2013 Mar-2013
TOTALCOUNT 761 647 671
Charge 126888 119995 151737.5
Payment 25705.4 26235.47 28704.41
A 1089.08 1020 745
B 2100.4 1947.25 1868.22
C 94246.55 84202.15 115673.7
D 0 0 0
E 0 0 0
I have seen the examples of pivot and unpivot, in pivot I don't get the column headers as row data, and in unpivot I didn't found an example where I can transpose multiple columns. I have another option to get this result in the code. But I want to know is it possible to get this kind of result in sql?
Edit
The result will give only for 3 or 4 months, not more than that.
Update : The first sample data is the actual data which I will get as a result of multiple joins and grouping on multiple tables, which I will store into a temp table. I tried to get the required result by modifying the query which is not possible because of the table structure. I managed to get the result as in the first sample data, but this is not what the client want to see!!! So I need to process the temp table data which will be only 3 to 4 rows into required output. The query to get the first result is select * from temp. The processing needs to be done on temp table result.
Update-2
I have tried the following query
declare #cols varchar(max)
select #cols = STUFF((select ', ' + MonthYear
from #tmp for xml path('')),1,1,'')
declare #query varchar(max)
set #query =
'select ''TOTAL'' as Data,' +#cols+' from
(select MonthYear,TOTALCLAIMS from #tmp)st
pivot
(
MAX(TOTAL) for MonthYear in (' + #cols + ')
)pt;'
Which gave me the first row correctly!!! But I tried to use union as
set #query =
'select ''TOTAL'' as Data,' +#cols+' from
(select MonthYear,TOTALCLAIMS from #tmp)st
pivot
(
MAX(TOTAL) for MonthYear in (' + #cols + ')
)pt;
union
select ''CHARGES'' as Data,' +#cols+' from
(select MonthYear,TOTALCLAIMS from #tmp)st
pivot
(
MAX(CHARGES) for MonthYear in (' + #cols + ')
)pt;'
Which gives an error as incorrect syntax near union. Any one know how to union pivot results? Or is there any better way to do this?
Thank You.
I have tried this code. Please check and let me know if it works
I know that it doesnt look so good. Also not sure how it will be performance wise.
--Can have more columns like A,B,...
DECLARE #tbl TABLE
(
TOTAL INT,
CHARGE FLOAT,
PAYMENT FLOAT,
MONTHYEAR VARCHAR(50)
)
--Test data
INSERT INTO #tbl SELECT 661, 157832.24, 82967.80, 'Oct2013'
INSERT INTO #tbl SELECT 612, 95030.52, 17824.28, 'Nov2013'
INSERT INTO #tbl SELECT 584 ,90256.35, 16732.91, 'Dec2013'
--Can be a physical table
CREATE TABLE #FinalTbl
(
DATA VARCHAR(100)
)
--inserted hardcode records in data column. To add it dynamically you would need to loop through information_schema.columns
--SELECT *
--FROM information_schema.columns
--WHERE table_name = 'tbl_name'
INSERT INTO #FinalTbl
VALUES ('TOTAL')
INSERT INTO #FinalTbl
VALUES ('CHARGE')
INSERT INTO #FinalTbl
VALUES ('PAYMENT')
DECLARE #StartCount INT, #TotalCount INT, #Query VARCHAR(5000), #TOTAL INT,#CHARGE FLOAT,#PAYMENT FLOAT,#MONTHYEAR VARCHAR(50)
SELECT #TotalCount = COUNT(*) FROM #tbl;
SET #StartCount = 1;
WHILE(#StartCount <= #TotalCount)
BEGIN
SELECT #TOTAL = TOTAL,
#CHARGE = CHARGE,
#PAYMENT = PAYMENT,
#MONTHYEAR = MONTHYEAR
FROM
(SELECT ROW_NUMBER() over(ORDER BY MONTHYEAR) AS ROWNUM, * FROM #tbl) as tbl
WHERE ROWNUM = #StartCount
SELECT #Query = 'ALTER TABLE #FinalTbl ADD ' + #MONTHYEAR + ' VARCHAR(1000)'
EXEC (#Query)
SELECT #Query = 'UPDATE #FinalTbl SET ' + #MONTHYEAR + ' = ''' + CONVERT(VARCHAR(50), #TOTAL) + ''' WHERE DATA = ''TOTAL'''
EXEC (#Query)
SELECT #Query = 'UPDATE #FinalTbl SET ' + #MONTHYEAR + ' = ''' + CONVERT(VARCHAR(50), #CHARGE) + ''' WHERE DATA = ''CHARGE'''
EXEC (#Query)
SELECT #Query = 'UPDATE #FinalTbl SET ' + #MONTHYEAR + ' = ''' + CONVERT(VARCHAR(50), #PAYMENT) + ''' WHERE DATA = ''PAYMENT'''
EXEC (#Query)
SELECT #StartCount = #StartCount + 1
END
SELECT * FROM #FinalTbl
DROP TABLE #FinalTbl
Hope this helps
I would imagine the reason you are only getting 3 or 4 months is because you don't have data for the missing months? If you want to display columns for missing months you will need to either:
Create a Table datatype with all the months you want to display
and left join the remainder of the tables to it in your query. You
could then use the PIVOT function as normal.
If you know how many columns up front i.e. one for each month in a particular year and it won't change, you can simply use CASE
Statements (one for each month) to transpose the data without the
PIVOT operator.
I can provide examples if needed.
Select Month(Mdate)md,'A' AS Col,sum(A) as a from Product group by Month(MDate)
union all
Select Month(Mdate)md,'B',sum(b) as a from Product group by Month(MDate)
union all
Select Month(Mdate)md,'C',sum(c) as a from Product group by Month(MDate)
union all
Select Month(Mdate)md,'D',Count(A) as a from Product group by Month(MDate)
Try Pivot with the above query you may to get required result....