How can I join the results of multiple pivot queries together horizontally? - sql

I may not have phrased the question clearly so I'll clarify it here.
I've got a VB.NET system that displays data. To display data, I have the following SQL stored procedure that makes use of pivot:
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(form_column_id) from
GetFormColumns(#formTemplateId) FOR XML PATH(''),
TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
set #query = N' select *
from
(select row_number as Row,fc.form_column_id, fdd.data
from
form_data_h fdh
inner join form_data_d fdd on fdd.form_data_h_id = fdh.form_data_h_id
inner join form_column fc on fc.form_column_id = fdd.form_column_id
inner join column_header c on c.column_header_id=fc.column_header_id
where fdh.is_active = 1 and fdh.form_data_h_id= ' +
CONVERT(varchar(10),#formDataHId) + ' and fc.is_active = 1
) src
pivot(
min(data)
for form_column_id in (' + #cols + N')
) piv'
execute(#query);
I had to make use of pivot because user data entry needs to be dynamic. So from this...
table results
The results now look like this.
pivot results
This data has different results filtered by particular parameters. Right now I've displayed the crop data for 2017. I want to join it with the crop data for 2018 (will change based on the Stored Procedure parameter #formDataHId).
That should result in something that looks like this...
2017 and 2018 results
Is there any way I can go about this in SQL or do I have to do that in VB.net? If so, how can I go about it?
Any ideas would be welcome because I'm a bit stumped right now. If users need to see data from let's say 2016 to 2019, it should be presented like that.

Pivot in SQL should be enough. If the structure of data in each year is the same, you can use UNION ALL between each year's data. Then use your query to pivot the combined years' data.
In my pivot function I use a table named Test to generate the pivot. I have 2 other tables Source2017 and Source2018. I insert both Source2017 and Source2018 using this query.
INSERT #Test
SELECT Date, Item, Quantity FROM #Source2017
UNION ALL
SELECT Date, Item, Quantity FROM #Source2018
If I only want data from 2017, I remove the Source2018 from the insert statement.
INSERT #Test
SELECT Date, Item, Quantity FROM #Source2017
Let's say I have more tables, Source2015 and Source2016. If I want to pivot all of them, just add the tables using UNION ALL.
INSERT #Test
SELECT Date, Item, Quantity FROM #Source2015
UNION ALL
SELECT Date, Item, Quantity FROM #Source2016
UNION ALL
SELECT Date, Item, Quantity FROM #Source2017
UNION ALL
SELECT Date, Item, Quantity FROM #Source2018
Full query:
IF OBJECT_ID('tempdb..#Test') IS NOT NUll DROP TABLE #Test
IF OBJECT_ID('tempdb..#Source2017') IS NOT NUll DROP TABLE #Source2017
IF OBJECT_ID('tempdb..#Source2018') IS NOT NUll DROP TABLE #Source2018
CREATE TABLE #Test
(
Date DATE,
Item VARCHAR(100),
Quantity INT
)
CREATE TABLE #Source2017
(
Date DATE,
Item VARCHAR(100),
Quantity INT
)
CREATE TABLE #Source2018
(
Date DATE,
Item VARCHAR(100),
Quantity INT
)
INSERT #Source2017 VALUES
('2017/01/01', 'Mango', 5),
('2017/01/01', 'Orange', 6),
('2017/01/02', 'Mango', 7),
('2017/01/02', 'Orange', 8),
('2017/01/02', 'Cherry', 9)
INSERT #Source2018 VALUES
('2018/01/01', 'Durian', 15),
('2018/01/02', 'Orange', 28),
('2018/01/03', 'Cherry', 19)
INSERT #Test
SELECT Date, Item, Quantity FROM #Source2017
UNION ALL
SELECT Date, Item, Quantity FROM #Source2018
DECLARE #SQL AS VARCHAR(MAX)
DECLARE #Columns AS VARCHAR(MAX)
DECLARE #Columns2 AS VARCHAR(MAX)
SELECT #Columns = COALESCE(#Columns + ',','') + QUOTENAME(Date)
FROM (SELECT DISTINCT Date FROM #Test) AS B
ORDER BY B.Date
SELECT #Columns2 = COALESCE(#Columns2 + ',','') + 'ISNULL(' + QUOTENAME(Date) + ', 0) AS [' + CAST(Date AS VARCHAR(100)) + ']'
FROM (SELECT DISTINCT Date FROM #Test) AS B
ORDER BY B.Date
SET #SQL = '
WITH PivotData AS
(
SELECT Date, Item, Quantity FROM #Test
)
SELECT
Item, ' + #Columns2 + '
FROM PivotData
PIVOT
(
SUM(Quantity)
FOR Date
IN (' + #Columns + ')
) AS PivotResult
ORDER BY Item'
EXEC(#SQL);
DROP TABLE #Test
DROP TABLE #Source2017
DROP TABLE #Source2018
Result:
+--------+------------+------------+------------+------------+------------+
| Item | 2017-01-01 | 2017-01-02 | 2018-01-01 | 2018-01-02 | 2018-01-03 |
+--------+------------+------------+------------+------------+------------+
| Cherry | 0 | 9 | 0 | 0 | 19 |
| Durian | 0 | 0 | 15 | 0 | 0 |
| Mango | 5 | 7 | 0 | 0 | 0 |
| Orange | 6 | 8 | 0 | 28 | 0 |
+--------+------------+------------+------------+------------+------------+

Related

Dynamic Way To Transpose SQL Table Similar to Excel Functionality

I've looked around a good amount and haven't found quite the correct solution to what I think is a very simple problem. Everything I find focuses on one value being tranposed, but here I have a bunch.
I have this table currently and I want to transpose it exactly how Excel would. What is the easiest way to do this?
What I have:
nodeid | Headcount | FTE | Count of Part-Time Employees | Count of Non-Permanent Employees |
Actuals | 12 | 13 | 23 | 35 |
Targets | 15 | 15 | 25 | 25 |
What I want:
nodeid | Actuals | Targets |
Headcount | 12 | 15 |
FTE | 13 | 15 |
Count of Part-Time Employees | 23 | 25 |
Count of Non-Permanent Employees | 35 | 25 |
If 2016+, you can use a bit of JSON to "dynamically" unpivot your data, and then simply apply a PIVOT
Example
Declare #YourTable Table ([nodeid] varchar(50),[Headcount] int,[FTE] int,[Count of Part-Time Employees] int,[Count of Non-Permanent Employees] int) Insert Into #YourTable Values
('Actuals',12,13,23,35)
,('Targets',15,15,25,25)
Select *
From (
Select A.NodeID
,B.*
From #YourTable A
Cross Apply (
Select [Node] = [Key]
,[Value] = try_convert(int,Value)
From OpenJson( (Select A.* For JSON Path,Without_Array_Wrapper )) ) B
Where try_convert(int,value) is not null
) src
Pivot ( max(Value) for [NodeID] in ([Actuals],[Targets]) ) pvt
Order By Node desc
Returns
Node Actuals Targets
Headcount 12 15
FTE 13 15
Count of Part-Time Employees 23 25
Count of Non-Permanent Employees 35 25
Note: If <2016 there is an similar XML approach.
You can use unpivot and pivot to achieve that.
try the following:
DECLARE #tab TABLE
(nodeid VARCHAR(100),
Headcount INT,
FTE INT,
[Count of Part-Time Employees] INT,
[Count of Non-Permanent Employees] INT
);
INSERT INTO #tab SELECT 'Actuals', 12, 13, 23, 35;
INSERT INTO #tab SELECT 'Targets', 15, 15, 25, 25;
SELECT *FROM #tab;
DROP TABLE IF EXISTS #temp;
SELECT *
INTO #temp
FROM
(
SELECT nodeid,
Headcount,
FTE,
[Count of Part-Time Employees],
[Count of Non-Permanent Employees]
FROM #tab
) t UNPIVOT(val FOR col IN(Headcount,
FTE,
[Count of Part-Time Employees],
[Count of Non-Permanent Employees])) upvt;
DECLARE #collist VARCHAR(MAX);
SELECT #collist = STUFF(
(
SELECT DISTINCT ',' + QUOTENAME(nodeid)
FROM #temp
ORDER BY ',' + QUOTENAME(nodeid) FOR XML PATH('')
), 1, 1, '');
DECLARE #sql VARCHAR(MAX)= 'select col as nodeid, Actuals, Targets
from #temp t
pivot
(
max(val) for nodeid IN (' + #collist + ')
)pvt';
EXEC (#sql);
Please see the db<>fiddle here

SQL How to pivot two columns of data into different columns?

This is the table I have:
| Scheme Code | MonthYear | Revenue | Revenue2 |
|-------------|-----------|---------|----------|
| 18VDA | 2018.1 | 100 | 50 |
| 18VDA | 2018.2 | 200 | 100 |
| 18VDA | 2018.3 | 200 | 150 |
and I want to pivot it to like this:
| Scheme Code | 2018.1 A | 2018.2 A | 2018.3 A | 2018.1 B | 2018.2 B | 2018.3 B |
|-------------|----------|----------|----------|----------|----------|----------|
| 18VDA | 100 | 200 | 200 | 50 | 100 | 150 |
How do I do it so that it pivots in MonthYear, but it duplicates it for both Revenue and Revenue2?
Thanks
EDIT: Messed up the output table I was hoping for! I've edited the actual output table I want to see!
EDIT 2:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
Select #cols = STUFF((SELECT ',' + QUOTENAME([MonthYear])
from tableA
group by [MonthYear]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT *
FROM ( SELECT [Scheme Code], MonthYear ,[Revenue]
FROM TableA
) a
PIVOT(sum(Revenue) for MonthYear in (' + #cols + ')
) as RevenueMonth
ORDER BY [Scheme Code]'
execute(#query);
This code I wrote will do it for just one column, and I get the output like this:
| Scheme Code | 2018.1 | 2018.2 | 2018.3 |
|-------------|--------|--------|--------|
| 18VDA | 100 | 200 | 200 |
My suggestion always is to try to write your query as a hard-coded or static version first before diving into dynamic SQL. This let's you get the final result you want with a smaller subset of data and you can verify that you have the logic correct.
I would tackle this by performing an UNPIVOT of the two Revenue columns first, then look at applying the PIVOT function. To UNPIVOT you can use either the UNPIVOT function or you can use CROSS APPLY with a UNION ALL to convert your two Revenue columns into a single column. A static version of the query would be similar to this:
select *
from
(
select
t.[Scheme Code],
new_colname = concat(t.[MonthYear], ' ', r.colname),
r.colvalue
from yourtable t
cross apply
(
select 'A', Revenue union all
select 'B', Revenue2
) r (colname, colvalue)
) d
pivot
(
sum(colvalue)
for new_colname in ([2018.1 A], [2018.2 A], [2018.3 A], [2018.1 B], [2018.2 B], [2018.3 B])
) p;
You'll notice that in the CROSS APPLY I added a column with the A or B that I use to identify either the Revenue or Revenue2 columns. This is then used to create the new column names for the PIVOT.
This should generate the result you want. Now to do this dynamically, you just need to convert the SQL to dynamic code. You can use the following to get the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
Select #cols = STUFF((SELECT ',' + QUOTENAME(concat([MonthYear], x.col))
from yourtable
cross join (select col = ' A' union all select ' B') x
group by [MonthYear], x.col
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT *
FROM
(
select
t.[Scheme Code],
new_colname = concat(t.[MonthYear], '' '', r.colname),
r.colvalue
from yourtable t
cross apply
(
select ''A'', Revenue union all
select ''B'', Revenue2
) r (colname, colvalue)
) a
PIVOT
(
sum(colvalue) for new_colname in (' + #cols + ')
) as x
ORDER BY [Scheme Code]';
exec sp_executesql #query;
Both of these should generate the same results (dbfiddle demo)
Do it with CASE and dynamic sql.
DECLARE #colsA AS NVARCHAR(MAX),
#colsB AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsA = (SELECT ', sum(case [MonthYear] when ''' + [MonthYear] + ''' then Revenue end)' + QUOTENAME([MonthYear] + ' A')
from tableA
group by [MonthYear]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'),
#colsB = (SELECT ', sum(case [MonthYear] when ''' + [MonthYear] + ''' then Revenue2 end)' + QUOTENAME([MonthYear] + ' B')
from tableA
group by [MonthYear]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)');
Set #query = 'select [Scheme Code]' + #colsA + #colsB + ' from TableA group by [Scheme Code] order by [Scheme Code];';
print #query;

How can use PivotTable in SQL Server with temporary table

Very new to SQL Server, at this time I want to use a query with a Pivot table but something is bat, Is there some one could be help me to find my error I appreciate. Regards In the first part I create a dummy table called DateTemp in the second part, I join two tables the DateTemp and datcpc tables, now I want to use a pivot table, but I get an error near to pivot section.
My code:
// First Part
DECLARE #StartDate datetime
DECLARE #EndDate datetime
SELECT #StartDate = '2018-01-01', #EndDate = '2018-11-08'
SELECT #StartDate = #StartDate - (DATEPART(DD, #StartDate) - 1)
DECLARE #DateTemp TABLE (TheDate DATETIME)
WHILE (#StartDate <= #EndDate)
BEGIN
INSERT INTO #DateTemp
VALUES (#StartDate)
SELECT #StartDate = DATEADD(DAY, 1, #StartDate)
END
// Second part
SELECT
CYALA, CYALB
FROM
(SELECT DISTINCT
fechab 'FECHA', clapla 'CLAVEPLANTA', clapro 'CLAVE PRODUCTO',
CAST(SUM(cantid) AS NUMERIC(9, 2)) 'ACTIVIDAD'
FROM
(datcpc
LEFT JOIN
(SELECT TheDate
FROM #DateTemp
WHERE TheDate >= '05/01/2018') NT ON datcpc.fechab = NT.TheDate)
WHERE
datcpc.fechab >= '01/05/2018'
AND datcpc.fechab >= '01/05/2018'
AND (clapla = 'CYALA' OR clapla = 'CYALB' OR clapla = 'CYAZC')
AND datcpc.tipflu = 'C'
GROUP BY
fechab, clapla, clapro) AS SOURCE
PIVOT
(SUM(SOURCE.ACTIVIDAD)
FOR SOURCE.CLAVEPLANTA IN (CYALA, CYALB)
) AS PIVOTABLE
Test the suggested answers, without success. Try a simpler example and even then the error is set as "System.Data.SqlClient.SqlException: 'Line 1: Incorrect syntax near 'PIVOT'.'", I do not know if it is the server configuration or something about it. I use a connection to the server via Visual Studio 2017 via SqlConnection my new easier codes is listed below
SELECT DISTINCT [CLAVEPLANTA], [ACTIVIDAD]
FROM(
SELECT fechab AS [FECHA], clapla AS [CLAVEPLANTA], CAST(SUM(cantid) AS NUMERIC(9,2) ) AS [ACTIVIDAD] FROM datcpc"
WHERE datcpc.fechab >= '01/05/2018'
AND (clapla='CYALA' OR clapla='CYALB' OR clapla='CYAZC')
GROUP BY fechab, clapla
) AS [SO]
PIVOT(SUM([SO.ACTIVIDAD]) FOR [SO.CLAVEPLANTA] IN ([CYALA], [CYALB])) AS [PVT];
I really apreciate you help
I am going to provide 2 variants of a "dynamic pivot" which I hope will assist:
Some sample data:
create table temp
(
date datetime,
category varchar(3),
amount money
)
insert into temp values ('1/1/2012', 'ABC', 1000.00)
insert into temp values ('2/1/2012', 'DEF', 500.00)
insert into temp values ('2/1/2012', 'GHI', 800.00)
insert into temp values ('2/10/2012', 'DEF', 700.00)
insert into temp values ('3/1/2012', 'ABC', 1100.00)
Now a query that will "pivot" that data into columns per day:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(convert(char(10), c.[date],121))
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT category, ' + #cols + ' from
(
select convert(char(10), [date],121) [date]
, amount
, category
from temp
) x
pivot
(
sum(amount)
for [date] in (' + #cols + ')
) p '
execute(#query)
The result looks like this:
+----------+------------+------------+------------+------------+
| category | 2012-01-01 | 2012-02-01 | 2012-02-10 | 2012-03-01 |
+----------+------------+------------+------------+------------+
| ABC | 1000,0000 | NULL | NULL | 1100,0000 |
| DEF | NULL | 500,0000 | 700,0000 | NULL |
| GHI | NULL | 800,0000 | NULL | NULL |
+----------+------------+------------+------------+------------+
Now, this query "pivots" category into columns:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.category)
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT convert(char(10),date,121) date, ' + #cols + ' from
(
select date
, amount
, category
from temp
) x
pivot
(
max(amount)
for category in (' + #cols + ')
) p '
execute(#query)
The result looks like this:
+------------+-----------+----------+----------+
| date | ABC | DEF | GHI |
+------------+-----------+----------+----------+
| 2012-01-01 | 1000,0000 | NULL | NULL |
| 2012-02-01 | NULL | 500,0000 | 800,0000 |
| 2012-02-10 | NULL | 700,0000 | NULL |
| 2012-03-01 | 1100,0000 | NULL | NULL |
+------------+-----------+----------+----------+
see these as a live demo here: 2 variants of TSQL pivot tables
origin of these examples Dynamic SQL PIVOT
some suggestions:
--Second part
SELECT
CYALA,CYALB -- you need to specify more columns here
FROM (
SELECT DISTINCT -- distinct is not needed when grouping, remove this
fechab 'FECHA'
,clapla 'CLAVEPLANTA'
,clapro 'CLAVE PRODUCTO'
,CAST(SUM(cantid) AS numeric(9, 2)) 'ACTIVIDAD'
/* if you are creating the temporal table to get EVERY date
, then #DateTemp should be the base table, and left join the [datcpc] */
FROM (datcpc
LEFT JOIN (
SELECT
TheDate
FROM #DateTemp
WHERE TheDate >= '05/01/2018' -- use YYYMMDD or YYYY-MM-DD consistently
) NT
ON datcpc.fechab = NT.TheDate)
WHERE datcpc.fechab >= '01/05/2018'
AND datcpc.fechab >= '01/05/2018' -- repeated, not needed
AND clapla IN('CYALA','CYALB','CYAZC') -- use IN()
AND datcpc.tipflu = 'C'
GROUP BY
fechab ,clapla ,clapro
) AS SOURCE
PIVOT (
SUM(SOURCE.ACTIVIDAD)
FOR SOURCE.CLAVEPLANTA IN (CYALA, CYALB) -- did you want dates here? (as the pivot columns)
) AS PIVOTABLE

SQL Server Pivot on multiple fields

I have searched this website for all possible solutions but still can't find an answer for my Pivot problem.
I have a table with the following data.
Portfolio | Date | TotalLoans | ActiveLoans | TotalBalance
--------------------------------------------------------------------
P1 | 2015-12-31 | 1,000 | 900 | 100,000.00
P1 | 2015-11-30 | 1,100 | 800 | 100,100.00
P1 | 2015-10-31 | 1,200 | 700 | 100,200.00
I am trying to create a pivot with the following output (only where Portfolio = P1)
Field | 2015-12-31 | 2015-11-30 | 2015-10-31 |
-----------------------------------------------------
TotalLoans | 1,000 | 1,100 | 1,200 |
ActiveLoans | 900 | 800 | 700 |
TotalBalance | 100,000 | 100,100 | 100,200 |
Ideally, I am looking for a dynamic pivot, but a static query would do as well and I can try a dynamic query out of that.
You need first to UNPIVOT your table. You can do it using this query:
SELECT Portfolio, [Date], Val, ColType
FROM (SELECT Portfolio,
[Date],
TotalLoans,
ActiveLoans,
TotalBalance
FROM mytable
WHERE Portfolio = 'P1') AS srcUnpivot
UNPIVOT (
Val FOR ColType IN (TotalLoans, ActiveLoans, TotalBalance)) AS unpvt
Output:
Portfolio Date Val ColType
===============================================
P1 2015-12-31 1000 TotalLoans
P1 2015-12-31 900 ActiveLoans
P1 2015-12-31 100000 TotalBalance
P1 2015-11-30 1100 TotalLoans
P1 2015-11-30 800 ActiveLoans
P1 2015-11-30 100100 TotalBalance
P1 2015-10-31 1200 TotalLoans
P1 2015-10-31 700 ActiveLoans
P1 2015-10-31 100200 TotalBalance
Note: All unpivoted fields must be of the same type. The query above assumes a type of int for all fields. If this is not the case then you have to use CAST.
Using the above query you can apply PIVOT:
SELECT Portfolio, ColType, [2015-12-31], [2015-11-30], [2015-10-31]
FROM (
... above query here ...
PIVOT (
MAX(Val) FOR [Date] IN ([2015-12-31], [2015-11-30], [2015-10-31])) AS pvt
This is Giorgos Betsos solution as dynamic SQL. This will deal without the need to write the date values explicitly.
Please: If you like this: Do not mark this solution as accepted, set the acceptance to Giorgos Betsos. There's the hard work! But you may vote on it :-)
CREATE TABLE #tbl(Portfolio VARCHAR(10),[Date] DATE,TotalLoans DECIMAL(10,4),ActiveLoans DECIMAL(10,4),TotalBalance DECIMAL(10,4));
INSERT INTO #tbl VALUES
('P1','20151231',1000,900,100000.00)
,('P1','20151130',1100,800,100100.00)
,('P1','20151031',1200,700,100200.00);
DECLARE #pvtColumns VARCHAR(MAX)=
(
STUFF(
(
SELECT DISTINCT ',['+CONVERT(VARCHAR(10), [Date] ,126) + ']'
FROM #tbl
FOR XML PATH('')
)
,1,1,'')
);
DECLARE #cmd VARCHAR(MAX)=
'SELECT Portfolio, ColType, ' + #pvtColumns +
' FROM (
SELECT Portfolio, [Date], Val, ColType
FROM (SELECT Portfolio,
[Date],
TotalLoans,
CAST(ActiveLoans AS DECIMAL(10,4)) AS ActiveLoans,
TotalBalance
FROM #tbl AS mytable
WHERE Portfolio = ''P1'') AS srcUnpivot
UNPIVOT (
Val FOR ColType IN (TotalLoans, ActiveLoans, TotalBalance)) AS unpvt
) AS srcPivot
PIVOT (
MAX(Val) FOR [Date] IN (' + #pvtColumns + ')) AS pvt';
EXEC (#cmd);
You need to use Dyanmic SQL and construct them. See examples at http://social.technet.microsoft.com/wiki/contents/articles/17510.t-sql-dynamic-pivot-on-multiple-columns.aspx
Here is the code
CREATE procedure CrossTab
(
#select varchar(2000),
#PivotCol varchar(100),
#Summaries varchar(100),
#GroupBy varchar(100),
#OtherCols varchar(100) = Null
)
AS
set nocount on
set ansi_warnings off
declare #sql varchar(8000)
Select #sql = ''
Select #OtherCols= isNull(', ' + #OtherCols,'')
create table #pivot_columns (pivot_column_name varchar(100))
Select #sql='select ''' + replace( + #PivotCol,',',''' as pivot_column_name union all select ''')+''''
insert into #pivot_columns
exec(#sql)
select #sql=''
create table #pivot_columns_data (pivot_column_name varchar(100),pivot_column_data varchar(100))
Select #PivotCol=''
Select #PivotCol=min(pivot_column_name) from #pivot_columns
While #PivotCol>''
Begin
insert into #pivot_columns_data(pivot_column_name,pivot_column_data)
exec
(
'select distinct ''' + #PivotCol +''' as pivot_column_name, convert(varchar(100),' + #PivotCol + ') as pivot_column_data from
('+
#select
+'
) T'
)
Select #PivotCol=min(pivot_column_name) from #pivot_columns where pivot_column_name>#PivotCol
end
select
#sql = #sql + ', ' +
replace(
replace(
#Summaries,'(','(CASE WHEN ' + Pivot_Column_name + '=''' +
pivot_column_data + ''' THEN '
),
')[', ' END) as [' + pivot_column_data
)
from #pivot_columns_data
order by pivot_column_name
exec
(
'select ' + #GroupBy +#OtherCols +#sql +
' from (
'+
#select
+'
) T
GROUP BY ' + #GroupBy
)
drop table #pivot_columns
drop table #pivot_columns_data
set nocount off
set ansi_warnings on
Usage
EXEC CrossTab
'SELECT LastName, OrderDate,shipcountry FROM northwind..Employees Employees
INNER JOIN northwind..Orders Orders ON (Employees.EmployeeID=Orders.EmployeeID) ',
'shipcountry,Year(OrderDate)',
'Count(LastName)[]',
'LastName'
Do it in several steps:
if object_id('tempdb..#Data') is null
CREATE TABLE #Data
([Portfolio] varchar(2), [Date] datetime,
[TotalLoans] decimal(9,2), [ActiveLoans] int, [TotalBalance] decimal(9,2))
;
INSERT INTO #Data
([Portfolio], [Date], [TotalLoans], [ActiveLoans], [TotalBalance])
VALUES
('P1', '2015-12-31', 1000, 900, 100000.00),
('P1', '2015-11-30', 1100, 800, 100100.00),
('P2', '2015-10-31', 1200, 700, 100200.00)
;
WITH Transposed AS (
--First reorganise the data, creating unions like this, by column
--Assumption is that you are not interested in [Portfolio]
SELECT [Portfolio], [Date], [TotalLoans] AS Amount, 'TotalLoans' Field FROM #Data
UNION SELECT [Portfolio], [Date], [ActiveLoans], 'ActiveLoans' FROM #Data
UNION SELECT [Portfolio], [Date], [TotalBalance], 'TotalBalance' FROM #Data
)
SELECT Field, [2015-10-31], [2015-11-30], [2015-12-31] --You can build a string with all the dates from your original data source
FROM (
SELECT [Date], [Field], [Amount] FROM Transposed
) d
PIVOT (
MAX(Amount)
FOR [Date] IN ([2015-10-31], [2015-11-30], [2015-12-31])
) p

SQL Server - Convert columns to rows

I have a table on which simple select gives out put like below
I want to write a select statement to output like below
Can someone help me...
Since you are basically rotating your current columns of Sale, Income and Profit into rows and then move the month values to columns, then you will want to first unpivot the current columns, then pivot the months.
Depending on your version of SQL Server there are a few ways that you can unpivot the data. You can use the UNPIVOT function or CROSS APPLY:
select month, type, value
from yourtable
cross apply
(
select 'Sale', sale union all
select 'Income', Income union all
select 'Profit', Profit
) c (type, value)
See SQL Fiddle with Demo. This will convert your current data into:
| MONTH | TYPE | VALUE |
|-------|--------|-------|
| Jan | Sale | 100 |
| Jan | Income | 50 |
| Jan | Profit | 10 |
| Feb | Sale | 20 |
| Feb | Income | 40 |
Then you can use the PIVOT function to convert the months into your column headers.
select type, Jan, Feb, Mar, Apr
from
(
select month, type, value
from yourtable
cross apply
(
select 'Sale', sale union all
select 'Income', Income union all
select 'Profit', Profit
) c (type, value)
) d
pivot
(
sum(value)
for month in (Jan, Feb, Mar, Apr)
) piv;
See SQL Fiddle with Demo.
if you have an unknown number of months, then you can use dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct N',' + QUOTENAME(Month)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT type, ' + #cols + N'
from
(
select month, type, value
from yourtable
cross apply
(
select ''Sale'', sale union all
select ''Income'', Income union all
select ''Profit'', Profit
) c (type, value)
) x
pivot
(
sum(value)
for month in (' + #cols + N')
) p '
execute sp_executesql #query;
See SQL Fiddle with Demo
You Can Use UNPIVOT then PIVOT
THE BEST IS TO DO QUERY EMBEDED SQL
create DISTINCT COLUMS of months with STUFF function then
replace FOR oMonth IN ([January-2013], [February-2013], [March-2013], [April-2013])
here core query
SELECT
*
FROM
( SELECT
oMonth, value,col
from (
select DATENAME(month,oDate) + '-' + CAST(YEAR( oDate) as varchar) as oMonth, Sales ,Income,Profit
FROM SalesSource
)A
unpivot
(
value for col in ( Sales ,Income,Profit)
) u
) as sourceTable
PIVOT
(
sum( value)
FOR oMonth IN ([January-2013], [February-2013], [March-2013], [April-2013])
) AS PivotTable;