Rows to Columns RDLC - sql-server

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)

Related

MS SQL.Transform rows into columns

I have a simple table. As a result I need to get names of numeric columns and paste like rows and then paste its values like columns.Here is an example of table:
As a result I need to receive something like this:
I tried to get the result with PIVOT, but I have not the correct answer.
select * from (
select col1, 'val' + cast(row_number()over(partition by col1 order by col1) as nvarchar(20)) ColVal
from mytbl
) tmp
pivot (
min(col1) for ColVal in (val1,val2)
) pvt
In this case you need to unpivot first, then pivot back:
DROP TABLE IF EXISTS dbo.temp
DROP TABLE IF EXISTS dbo.temp2
CREATE table dbo.temp(col1 INT, col2 INT, col3 INT);
INSERT INTO temp VALUES (27,93,80),(32,84,72),(46,68,75),(38,79,73),(23,77,84);
DECLARE #colsUnpivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
-- first unpivot to key value pairs
select #colsUnpivot
= stuff((select ','+quotename(C.column_name)
from information_schema.columns as C
where C.table_name = 'temp' and
C.column_name like 'col%'
for xml path('')), 1, 1, '')
set #query
= 'SELECT ''val'' + convert(varchar, i) as id,
name,
val
INTO dbo.temp2
FROM
(
SELECT *, row_number() over (order by col1) as i
from temp
) a
UNPIVOT
(
val
FOR name IN ('+ #colsunpivot +')
) u'
exec sp_executesql #query;
-- now pivot back
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', ' + QUOTENAME(id)
FROM (SELECT DISTINCT id FROM dbo.temp2) AS x;
SET #query = N'
SELECT name, ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT id, name, val
from temp2
) AS j
PIVOT
(
SUM(val) FOR id IN ('
+ STUFF(REPLACE(#columns, ', [', ',['), 1, 1, '')
+ ')
) AS p;';
EXEC sp_executesql #query;
I adapted two separate scripts I had lying around, hence the two parts and the intermediate temp2 table. You can probably mash both together with a bit of elbow grease, but this should get you most of the way there.
Also adding the id (to get val1, val2 etc) dynamically means the results are sorted by col1 (val1 will have the lowest col1) but you were doing something similar in your attempt so I assume this is ok. If not, you will need to add an identity column to the data first and use that in place of the row_number()

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'
;

Pivot getting multiple records

I'm working on pivot functionality.
I'm having 2 tables one is userinfo and another is hobbies.
My table will be as like below image.
I'm saving the hobbies with comma separated data in userinfo.
I want all the comma separated hobbies with their respective column names.
I tried, but getting indivdual records for each hobbies instead of the single row
as like below image.
My code is as follows :
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
--drop table Temptbl1
--drop table Temptbl2
IF EXISTS (SELECT * FROM Temptbl1)
drop table Temptbl1
IF EXISTS (SELECT * FROM Temptbl2)
drop table Temptbl2
SELECT * INTO Temptbl1 FROM UserInfo CROSS APPLY dbo.SplitData(Hobbies,',')
--select * from Temptbl1
Select * into Temptbl2 from Temptbl1 s,Hobbies h where s.DividedItem=h.Hid
--select * from Temptbl2
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(HName) from Hobbies
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
print #cols
set #query = 'SELECT distinct UId,UName,UAge,Hid, '+#cols +' from ( select
* from Temptbl2 )
x
pivot
(max(DividedItem) for HName in (' + #cols + ') ) p '
select * from Temptbl2
exec(#query)
You are selecting all columns from the temptbl2 and you do not need them. The Hid column is selected there and it is making the rows unique and the pivot fails to aggregate the results correctly. Just change it to this:
set #query = 'SELECT distinct UId,UName,UAge, '+#cols +' from ( select UId,UName,UAge, DividedItem, HName
from Temptbl2 )
x
pivot
(max(DividedItem) for HName in (' + #cols + ') ) p '
And you will be OK.
Here is full working example on SQL Server 2016 SP1. I am using string_split to split the data and temporary table to store it. Also, change a little bit the join syntax (your is obsolete and should not be used). You can adapt the code below to work on your environment easily:
DECLARE #hobbies TABLE
(
[HiD] INT
,[HName] VARCHAR(12)
);
INSERT INTO #hobbies ([HiD], [HName])
VALUES (1, 'Reading')
,(2, 'Singing')
,(3, 'Dancing');
DECLARE #UserInfo TABLE
(
[UID] INT
,[UName] VARCHAR(12)
,[UAddress] VARCHAR(12)
,[UAge] TINYINT
,[Hobbies] VARCHAR(12)
)
INSERT INTO #UserInfo ([UID], [UName], [UAddress], [UAge], [Hobbies])
VALUES (1, 'Abc', 'addr1', 25, '2,3')
,(2, 'Def', 'addr2', 27, '1,2,3')
,(3, 'Ghi', 'addr3', 20, '1');
DROP TABLE IF EXISTS #TEST;
SELECT *
INTO #TEST
FROM #UserInfo UI
CROSS APPLY string_split(UI.[Hobbies], ',') HS
INNER JOIN #hobbies H
ON HS.[value] = h.[HiD]
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
Select #cols = STUFF((SELECT distinct ',' + QUOTENAME(HName) from #hobbies
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
set #query = 'SELECT distinct UId,UName,UAge, '+#cols +' from ( select uid, uname, uage, hname, value
from #TEST )
x
pivot
(max(value) for HName in (' + #cols + ') ) p '
exec(#query)

SQL Server Pivot and Sort

I have a shop order table with the Item code, description ReleaseDate and Required quantity.
How to query in a pivot table format in such a way that the results will be pivoted using Year+Month of [ReleaseDate] in sorting order from oldest date to latest date. Using the Year+Month as a column.
This is my query but it fails.
--Declare necessary variables
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
--Get unique values of pivot column
SELECT #PivotColumns = COALESCE(#PivotColumns + ',','') + QUOTENAME([YEARMONTH])
FROM (SELECT DISTINCT CONVERT(char(6), cast([releaseddate] as date), 112 ) as [YEARMONTH] FROM [dbo].[ShopOrder]) as PivotQuery
SELECT #PivotColumns
--Create the dynamic query with all the values for
--pivot column at runtime
SET #SQLQuery =
N'SELECT ItemCode, ' + #PivotColumns + '
FROM [dbo].[ShopOrder]
PIVOT( SUM(RequiredQty)
FOR [releaseddate] IN (' + #PivotColumns + ')) AS P'
SELECT #SQLQuery
--Execute dynamic query
EXEC sp_executesql #SQLQuery
This is the original record
Results query must be like this
Here I have tried to execute the pivot with your provided data.
Query
Select
[ItemCode],
[Description],
[2017/8],
[2017/9]
from
(
select cast(year(ReleasedDate) as nvarchar)+'/'+cast(month(ReleasedDate) as nvarchar) as ReleasedDate,ItemCode,Description,RequiredQty
from shoporder) as PivotData
Pivot
(
sum(RequiredQty) for ReleasedDate in
([2017/8],[2017/9])) as Pivoting
order by ItemCode
Output:
Fiddle
You are not pivoting correctly and the column names should be generated in a single string. Try this:
CREATE TABLE ShopOrder (ItemCode VARCHAR(100),[Description] VARCHAR(100),ReleaseDate DATE, RequiredQty INT)
GO
INSERT INTO ShopOrder
VALUES
('A','SLEEVE NUT','08/01/2017',19200)
,('A','SLEEVE NUT','08/02/2017',18000)
,('A','SLEEVE NUT','09/01/2017',17000)
,('B','STARTER','08/03/2017',10000)
,('B','STARTER','08/04/2017',18000)
,('B','STARTER','09/15/2017',16000)
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
SET #PivotColumns = STUFF(( SELECT DISTINCT ',[' + CONVERT(char(6), cast(ReleaseDate as date), 112 ) + ']'
FROM ShopOrder
ORDER BY ',[' + CONVERT(char(6), cast(ReleaseDate as date), 112 ) + ']'
FOR XML PATH('')),1,1,'')
SET #SQLQuery =
N'
SELECT ItemCode,'+ #PivotColumns + '
FROM (SELECT ItemCOde,CONVERT(char(6), cast(ReleaseDate as date),112) ReleaseDate, RequiredQty
FROM ShopOrder) AS T
PIVOT( SUM(RequiredQty)
FOR ReleaseDate IN ('+#PivotColumns+')) AS P
'
SELECT #SQLQuery
--Execute dynamic query
EXEC sp_executesql #SQLQuery

Create table on SQL Server from dynamic pivot results

Is there a way to directly store the results of a dynamic pivot query into a fixed table? As the result is dynamic I can't create the table by specifying the columnnames and methods like "create table MyTable as (pivot select statement)" seem to fail on SQL server ("Incorrect syntax near the keyword 'AS'").
I have tried to format the SQL below to get a SELECT - INTO - FROM structure but failed to do so. Any help is obviously greatly appreciated!
The SQL used for the pivot is (build thanks to this great website!):
declare #pivot varchar(max), #sql varchar(max)
create table pivot_columns (pivot_column varchar(100))
insert into pivot_columns
select distinct DateField from MyTable order by 1
select #pivot=coalesce(#pivot+',','')+'['+pivot_column+']'from pivot_columns
set #sql = 'SELECT * FROM (select DateField, RefCode, SumField from MyTable) p
PIVOT
(sum(SumField) FOR DateField IN ( ' + #pivot + ') )
AS pvl'
drop table pivot_columns
exec (#sql)
Unless I am not following what you are trying to do you should be able to add the INTO mynewTable to your sql that you are going to execute and you should get the new table.
declare #pivot varchar(max), #sql varchar(max)
create table pivot_columns (pivot_column varchar(100))
insert into pivot_columns
select distinct DateField from MyTable order by 1
select #pivot=coalesce(#pivot+',','')+'['+pivot_column+']'from pivot_columns
set #sql = 'SELECT * INTO mynewTable FROM (select DateField, RefCode, SumField from MyTable) p
PIVOT
(sum(SumField) FOR DateField IN ( ' + #pivot + ') )
AS pvl'
drop table pivot_columns
exec (#sql)
I just test creating a new table in the following script and it gives me a new table that is in the DB for use:
create table t
(
[month] int,
[id] nvarchar(20),
[cnt] int
)
insert t values (4,'TOTAL',214)
insert t values (5,'TOTAL',23)
insert t values (6,'TOTAL',23)
insert t values (4,'FUNC',47)
insert t values (5,'FUNC',5)
insert t values (6,'FUNC',5)
insert t values (4,'INDIL',167)
insert t values (5,'INDIL',18)
insert t values (6,'INDIL',18)
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(month)
FROM t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT *
INTO tabletest from
(
select month, id, cnt
from t
) x
pivot
(
sum(cnt)
for month in (' + #cols + ')
) p '
execute(#query)
drop table t

Resources