Getting error when dynamically unpivoting in SQL Server 2012 - sql-server

The goal is to dynamically pivot data and then dynamically unpivot it.
I am getting an error saying Invalid ControlNo
I am assuming its because variable #colsUnpivot contains ControlNo column.
But how can I fix it? I definitely need that ControlNo.
IF OBJECT_ID('tempdb..##A') IS NOT NULL DROP TABLE ##A
IF OBJECT_ID('tempdb..#table1') IS NOT NULL DROP TABLE #table1
Create table #Table1 ( ControlNo INT, Bound INT, Declined INT, Rated INT, Quoted INT, QuoteStatus VARCHAR(50) )
INSERT INTO #Table1 (ControlNo, Bound, Declined, Rated, Quoted, QuoteStatus)
VALUES (1111,1,0,1,1,'Lost'),
(2222,0,1,0,1,'No Action'),
(3333,1,1,0,0,NULL),
(4444,1,0,0,1,'Lost'),
(5555,0,1,1,1,'No Action')
DECLARE #columns AS NVARCHAR(MAX),
#finalquery AS NVARCHAR(MAX);
SET #columns = STUFF((SELECT distinct ',' + QUOTENAME(QuoteStatus) FROM #Table1 FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
--PRINT #columns
set #finalquery = '
select p.controlno,
p.Bound,
p.Declined,
p.Rated,
p.Quoted,' + #columns + '
into ##A
from ( select ControlNo, Bound, Declined, Rated, Quoted, QuoteStatus
from #Table1
)a
pivot
(
COUNT(QuoteStatus)
for QuoteStatus IN (' + #columns + ')
)p '
exec(#finalquery)
--SELECT *
--FROM ##a
DECLARE #colsUnpivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsUnpivot
= stuff((select ','+quotename(C.name)
FROM tempdb.sys.columns c
WHERE c.object_id = OBJECT_ID('tempdb..##A')
for xml path('')), 1, 1, '')
--PRINT #colsUnpivot
set #query
= 'select ControlNo, Counts, Status
from ##A
unpivot
(
Counts
for Status in ('+ #colsunpivot +')
) u'
exec sp_executesql #query;
Output should look like this:

I assume your sample output was that, a sample, and you excluded the other control numbers. If so, changing the where clause in your stuff will remove that column from the unpivot group, and give you desired results. You can't return a column that you are pivoting or unpivoting.
IF OBJECT_ID('tempdb..##A') IS NOT NULL DROP TABLE ##A
IF OBJECT_ID('tempdb..#table1') IS NOT NULL DROP TABLE #table1
Create table #Table1 ( ControlNo INT, Bound INT, Declined INT, Rated INT, Quoted INT, QuoteStatus VARCHAR(50) )
INSERT INTO #Table1 (ControlNo, Bound, Declined, Rated, Quoted, QuoteStatus)
VALUES (1111,1,0,1,1,'Lost'),
(2222,0,1,0,1,'No Action'),
(3333,1,1,0,0,NULL),
(4444,1,0,0,1,'Lost'),
(5555,0,1,1,1,'No Action')
DECLARE #columns AS NVARCHAR(MAX),
#finalquery AS NVARCHAR(MAX);
SET #columns = STUFF((SELECT distinct ',' + QUOTENAME(QuoteStatus) FROM #Table1 FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
--PRINT #columns
set #finalquery = '
select p.controlno,
p.Bound,
p.Declined,
p.Rated,
p.Quoted,' + #columns + '
into ##A
from ( select *
from #Table1
)a
pivot
(
COUNT(QuoteStatus)
for QuoteStatus IN (' + #columns + ')
)p '
exec(#finalquery)
--SELECT *
--FROM ##a
DECLARE #colsUnpivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsUnpivot
= stuff((select ','+quotename(C.name)
FROM tempdb.sys.columns c
--notice i remove controlno here...
WHERE c.object_id = OBJECT_ID('tempdb..##A') and c.name <> 'controlno'
for xml path('')), 1, 1, '')
--PRINT #colsUnpivot
set #query
= 'select Controlno, Counts, Status
from ##A
unpivot
(
Counts
for Status in ('+ #colsunpivot +')
) u'
exec sp_executesql #query;
To get your exact output, then just add a where clause to the set #query.
set #query
= 'select Controlno, Counts, Status
from ##A
unpivot
(
Counts
for Status in ('+ #colsunpivot +')
) u
where controlno = 1111'

Related

How Do I Join A SQL Pivot Query That Uses Delare Statements to a Normal SQL Query

Sorry if this isn't the best way to ask this but I am stuck at this point, I have tried researching but to no avail, trying to join these two queries:
SELECT [id]
,[title]
,[desc]
FROM [localTest].[dbo].[main];
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME([Year]) from [localTest].[dbo].[Years] FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT [ID], ' + #cols + ' from (select [ID], [Year], [Amount] FROM [localTest].[dbo].[Years] ) x pivot (min([Amount]) for [Year] in (' + #cols + ')) p '
execute(#query);
Looking for the final result here:
enter image description here
I figured it out, here is my solution:
DECLARE #cols AS NVARCHAR(MAX);
SELECT #cols = STUFF((SELECT distinct ',' + QUOTENAME([Year]) FROM [localTest].[dbo].[Years] FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'');
DECLARE #Sql VARCHAR(max);
SELECT #Sql = 'SELECT * FROM [localTest].[dbo].[main] a join (
SELECT * FROM (
SELECT [ID] id, [Year], [Amount]
FROM [localTest].[dbo].[Years]
) x pivot (
min([Amount])
for [Year] IN ('+#cols+')
) p ) as b on a.[ID] = b.id';
EXECUTE(#Sql);
Insert the result of second query to a #temp table and join the #temp table to main table like below:
SELECT [id]
,[title]
,[desc]
FROM [localTest].[dbo].[main];
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME([Year]) from [localTest].[dbo].[Years] FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT [ID], ' + #cols + ' from (select [ID], [Year], [Amount] FROM [localTest].[dbo].[Years] ) x pivot (min([Amount]) for [Year] in (' + #cols + ')) p '
insert into #temp
execute(#query);
select * from [localTest].[dbo].[main] AS a inner join #temp as b on a.id = b.id

How can I dynamically convert row to columns and have different column name for each column

How can I convert rows into columns and create different name for each column?
create table #TempTable (InvoiceNum int,State varchar(2), ChargeName varchar(50), PercentageRate decimal(5,3), FlatRate decimal(5,2))
insert into #TempTable values (235736, 'AZ','Inspection & Policy Fee', NULL,250.00)
,(235736, 'AZ','Surplus Line Tax',0.03,NULL)
,(235736, 'AZ','Stamping Fee',0.002,NULL
)
I need something like that:
UPDATE:
Using example I was able to unpivot it but the result is not what I wanted to:
create table #TempTable (InvoiceNum int,State varchar(2), ChargeName varchar(50), PercentageRate decimal(5,3), FlatRate decimal(5,2))
insert into #TempTable values (235736, 'AZ','Inspection & Policy Fee', NULL,250.00)
,(235736, 'AZ','Surplus Line Tax',0.03,NULL)
,(235736, 'AZ','Stamping Fee',0.002,NULL)
--select * from #TempTable
Declare #SQL nvarchar(max),
#query nvarchar(max)
select #SQL = STUFF((SELECT ',' + QUOTENAME(ChargeName)
from #TempTable
group by ChargeName, InvoiceNum
order by InvoiceNum
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
--select #SQL
set #SQL = 'SELECT ' + #SQL + ' from
(
select PercentageRate, ChargeName
from #TempTable
) x
pivot
(
max(PercentageRate)
for ChargeName in (' + #SQL + ')
) p '
exec sp_executesql #SQL;
UPDATE:
Running below query gives me this:
Why ChargeName is not on the first row? I would expect to see it like this: What am I missing?
declare #TempTable table (InvoiceNum int,StateID varchar(2), ChargeName varchar(50), PercentageRate decimal(5,3), FlatRate decimal(5,2))
insert into #TempTable values (235736, 'AZ','Inspection & Policy Fee', NULL,250.00)
,(235736, 'AZ','Surplus Line Tax',0.03,NULL)
,(235736, 'AZ','Stamping Fee',0.002,NULL)
select
InvoiceNum,
ChargeName,
StateID,
PercentageRate,
FlatRate,
row_number() over (partition by InvoiceNum order by ChargeName) as RN
into #TempTable
from #TempTable #TempTable
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME(RN)
FROM (SELECT DISTINCT RN FROM #TempTable) AS RN
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
N'SELECT InvoiceNum, ' + #ColumnName + '
FROM #TempTable
PIVOT(MAX(ChargeName)
FOR RN IN (' + #ColumnName + ')) AS PVTTable'
EXEC sp_executesql #DynamicPivotQuery
drop table #TempTable
I would just join the temp table multiple times as needed.
Given your #TempTable
SELECT T1.InvoiceNum,
Tax1_Jurisdiction = T1.State, Tax1_TaxType = T1.ChargeName, Tax1_Percent = T1.PercentageRate, Tax1_FixedRate = T1.FlatRate,
Tax2_Jurisdiction = T2.State, Tax2_TaxType = T2.ChargeName, Tax2_Percent = T2.PercentageRate, Tax2_FixedRate = T2.FlatRate,
Tax3_Jurisdiction = T3.State, Tax3_TaxType = T3.ChargeName, Tax3_Percent = T3.PercentageRate, Tax3_FixedRate = T3.FlatRate
FROM #TempTable T1
JOIN #TempTable T2 ON T1.InvoiceNum = T2.InvoiceNum
JOIN #TempTable T3 ON T1.InvoiceNum = T3.InvoiceNum
WHERE T1.ChargeName = 'Inspection & Policy Fee'
AND T2.ChargeName = 'Surplus Line Tax'
AND T3.ChargeName = 'Stamping Fee'
;

Rows to Columns RDLC

i have data in below format. this data is coming through SQL Query.
i want to show it in below format either by query or by rdlc report.
You need to use dynamic SQL to make it.
From your expected result you can try to follow thoes step to make it.
use row_number function make row number by Name, because we need to join base on that row_number.
get the use MAX and MIN to make row number calendar table. from 1 to max(rn). the table can let use outer join
declare a var #tables to make the OUTER JOIN execute SQL (each LEFT JOIN maen a group of Crew#).
declare a var #col to make column, which you want to select (Employee) from each table.
then use execute dynamic execute it.
look like this.
create table T
(
Name varchar(50),
Employee VARCHAR(50)
)
insert into T values ('Crew#1','TR123');
insert into T values ('Crew#1','311');
insert into T values ('Crew#2','DDD');
insert into T values ('Crew#2','12121');
insert into T values ('Crew#1','SDDAS');
insert into T values ('Crew#3','31114312');
insert into T values ('Crew#3','DD14124D');
insert into T values ('Crew#3','1214124121');
insert into T values ('Crew#3','SDD412AS');
DECLARE #tables AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#col AS NVARCHAR(MAX);
SET #tables = STUFF((SELECT distinct ' LEFT JOIN ' + ' (SELECT * FROM CTE WHERE Name = '''+Name+''') '+QUOTENAME(Name)+' on t1.smallRN = '+QUOTENAME(Name)+'.rn'
FROM T
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #col = STUFF((SELECT distinct ', ' + QUOTENAME(Name)+'.Employee as '''+ QUOTENAME(Name) +''''
FROM T
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #col = substring(#col,1, len(#col))
set #query = '
WITH CTE AS (
SELECT *,ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name) rn
FROM T
),CTE1 AS(
SELECT MIN(rn) smallRN,MAX(rn) bigRN
FROM CTE
UNION ALL
SELECT smallRN+1,bigRN
FROM CTE1
WHERE smallRN < bigRN
)
SELECT '+#col+'
FROM CTE1 t1 ' + #tables
execute(#query)
sqlfiddle
Creatin tbale
First we will create a temp table where we will stock the data that you have and your table
create table #table1
(
[Crew Name] varchar(500) ,
Employee varchar(500)
)
INsert into #table1
values (....)
select * from #table1
Dynamic selection
then we will create a dynamic query to get the columns that we have, that way we can add as much crews as we want,
declare #DynamicPivotQuery as nvarchar(max)
declare #ColumnName as nvarchar(max)
select #ColumnName = ISNULL(#ColumnName +',','') + QUOTENAME([Crew Name])
from (select distinct [Crew Name] from #table1) as Country
set #DynamicPivotQuery = N'select ' +#ColumnName + '
from #table1
Pivot ( MAX(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
'
exec (#DynamicPivotQuery)
this way we will get only the first row for every column
so we have to find a way to aggregate and get the other columns as well just to demonstrate i will union the Mmin also this is where i stoped my testes but you can do more then this with some testes
now the union :
declare #DynamicPivotQuery as nvarchar(max)
declare #ColumnName as nvarchar(max)
select #ColumnName = ISNULL(#ColumnName +',','') + QUOTENAME([Crew Name])
from (select distinct [Crew Name] from #table1) as Country
set #DynamicPivotQuery = N'select ' +#ColumnName + '
from #table1
Pivot ( MAX(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
union
select ' +#ColumnName + '
from #table1
Pivot ( MIN(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
'
exec (#DynamicPivotQuery)
here is the result :
if you follow this way i'm sure that you will find a way to union all the result
You can add this result into a temp table
then add a column which will be a reference into this temp table
then use pivot function
To know more about pivot Visit :
https://msdn.microsoft.com/en-us/azure/data-lake-analytics/u-sql/pivot-and-unpivot-u-sql
you can use also SSIS to a very handy tool and easy to use
Using dynamic PIVOT if you dont have a set Crew columns.
DECLARE #ColumnString VARCHAR(256)
DECLARE #ColumnHeadrer VARCHAR(256)
DECLARE #sql varchar(1000)
CREATE TABLE #ColumnValue
(
Value VARCHAR(500),
ColumnHeader VARCHAR(256)
)
INSERT INTO #ColumnValue (Value, ColumnHeader)
SELECT DISTINCT '[' + CrewName + ']',
'ISNULL(' + CrewName + ','''') AS ' + CrewName
FROM CrewTable
SELECT #ColumnString = COALESCE(#ColumnString + ',', '') + Value,
#ColumnHeadrer = COALESCE(#ColumnHeadrer + ',', '') + ColumnHeader
FROM #ColumnValue
SET #sql =
'
SELECT ' + #ColumnHeadrer + '
FROM
(
SELECT Employee,
CrewName,
ROW_NUMBER() OVER(PARTITION BY CrewName ORDER BY CrewName) AS rnk
FROM CrewTable
) AS P
PIVOT
(
MAX(Employee) FOR [CrewName] IN ('+#ColumnString+')
) AS pv
'
EXEC (#sql)

ms sql pivot does not work

I'm trying to transpose a simple table from rows to columns with two string variables. I went trough several examples from the web without success. The number of rows will vary so I need to transpose the table dynamically. The following code at least does not produce an error but does not generate the result!
The sample table
create table #Encabezado
(
NodeName nvarchar(100),
NodeValue nvarchar(100)
)
INSERT INTO #Encabezado (NodeName, NodeValue) VALUES
('RUTEmisor','88888888-8'),
('RznSoc','EMPRESA DE PRUEBA'),
('GiroEmis','Informatica'),
('Acteco','1'),
('CdgSIISucur','59529595'),
('DirOrigen','Teatinos 120'),
('CmnaOrigen','Santiago'),
('CiudadOrigen','Santiago')
GO
The unpivot code
DECLARE #colsUnpivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsUnpivot
= stuff((select ','+quotename(C.column_name)
from information_schema.columns as C
where C.table_name = '#Encabezado' and
C.column_name like '%Name'
for xml path('')), 1, 1, '')
set #query
= 'select NodeName,
Nodevalue
from #Encabezado
unpivot
(
NodeName
for NodeName in ('+ #colsunpivot +')
) u'
exec sp_executesql #query;
Any help would be appreciated
Sequelspear once said : "To Pivot or UnPivot, That's the question."
declare #cols NVARCHAR(MAX) = stuff((select ','+quotename(Nodename) from #Encabezado group by Nodename for xml path('')),1,1,'');
declare #query NVARCHAR(MAX) = 'select * from #Encabezado pivot (max(NodeValue) for NodeName IN ('+ #cols +')) pvt';
exec sp_executesql #query;
To Dynamically Pivot
Declare#Cols AS NVARCHAR(MAX),#SQL AS NVARCHAR(MAX);
Set #Cols = Stuff((Select Distinct ',' + QuoteName(NodeName)
From #Encabezado
For XML Path(''), Type
).value('.', 'varchar(max)'),1,1,'')
Set #SQL = 'Select * From #Encabezado
Pivot (
max(NodeValue)
For [NodeName] in (' + #Cols + ')
) p '
Exec (#SQL)
Returns
Now, to unpivot, consider the following:
Declare #User table (ID int,Active bit,First_Name varchar(50),Last_Name varchar(50),EMail varchar(50))
Insert into #User values
(1,1,'John','Smith','john.smith#email.com'),
(2,0,'Jane','Doe' ,'jane.doe#email.com')
Declare #XML xml = (Select * from #User for XML RAW)
Select ID = r.value('#ID','int')
,Active = r.value('#Active','bit')
,Item = attr.value('local-name(.)','varchar(100)')
,Value = attr.value('.','varchar(max)')
From #XML.nodes('/row') as A(r)
Cross Apply A.r.nodes('./#*') AS B(attr)
Where attr.value('local-name(.)','varchar(100)') not in ('ID','Active')
Returns

How do I unpivot/pivot dynamically while keeping original order of my columns?

I'm making an accounting report by performing a bunch of calculations on a table and transposing it by unpivoting/pivoting so it matches the format I want.
The problem is when I unpivot the columns into the rows the resulting output automatically sorts the rows by alphabetical order. I want to know if there's a way to stop the unpivot from doing that and transposing the exact order of the columns into the rows.
Here's my code for the dynamic pivot/unpivot:
ALTER PROCEDURE dbo.GenerateFormattedFFOReport
AS
BEGIN
SET NOCOUNT ON;
DECLARE #COLSUNPIVOT AS NVARCHAR(MAX),
#QUERY AS NVARCHAR(MAX),
#COLSPIVOT AS NVARCHAR(MAX),
#COLSUNPIVOTORDER AS NVARCHAR(MAX)
SELECT #COLSUNPIVOT = STUFF((SELECT ','+QUOTENAME(C.NAME)
FROM SYS.COLUMNS C WITH(NOLOCK)
WHERE C.OBJECT_ID = OBJECT_ID('GenerateFFOReportData') AND C.NAME <> 'Quarter'
FOR XML PATH('')), 1, 1, '')
SELECT #COLSUNPIVOTORDER = STUFF
SELECT #COLSPIVOT = STUFF((SELECT ',' + QUOTENAME([Quarter])
FROM GenerateFFOReportData T FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
SELECT #COLSUNPIVOT
SET #QUERY
= 'SELECT HEADER, '+#COLSPIVOT+'
FROM
(
SELECT HEADER,[Quarter],VALUE FROM GenerateFFOReportData
UNPIVOT
(
VALUE FOR HEADER IN ('+#COLSUNPIVOT+')
) UNPIV
) SRC
PIVOT
(
SUM(VALUE)
FOR [Quarter] IN ('+#COLSPIVOT+')
) PIV'
EXEC (#QUERY)
END
GO
Thanks for any help you can give.

Resources