ms sql pivot does not work - sql-server

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

Related

Getting error when dynamically unpivoting in SQL Server 2012

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'

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

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)

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.

Trigger a dynamic SQL Server stored procedure to run every day

I have a dynamic stored procedure which runs in SSMS. Is it possible to convert this proc into a function so when ever I do
exec function stored.proc
I can run this from my ETL?
My query as below -
create procedure dbo.bear_load
as
set nocount on;
Declare #cols as NVARCHAR(MAX), #query as NVARCHAR(MAX), #Result as NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(FIELD_NAME)
from bear_crossjoin
group by Field_Name, FIELDNUMBER
order by FIELDNUMBER
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cols + N'
from
(
select substring, Field_Name,
rn = row_number() over(partition by field_name order by fieldnumber)
from bear_crossjoin
) x
pivot
(
max(substring)
for Field_Name in (' + #cols + N')
) p '
set #Result= ' select ' + #query
EXEC (#query)
GO
exec dbo.bear_load
Any help very much appreciated.
Arun

Resources