How to pivot table rows into columns with dynamic name - sql

I'm having a very tough time trying to figure out how to do
CID sUSER VALUE
------------------
001 235 10
001 188 20
001 04 5
002 235 11
002 188 12
002 04 13
I would like it displayed as follows
CID 04 188 235
-------------------
001 5 20 10
002 13 12 11
Can someone please show me the Sql code please ?

Lets Assume you have filtered data in #tmpCID; now try below script
Declare #sUser As Varchar(Max)
SELECT #sUser= Case isNull(#sUser,'')
When '' then '['+ Rtrim(sUser) + ']'
Else COALESCE(#sUser + ',[', ',') + Rtrim(sUser)+ ']'
End
FROM (SELECT DISTINCT sUser FROM #tmpCID) U
Declare #Query As Varchar(Max)
Set #Query='Select CID, ' + #sUser + ' From #tmpCID
Pivot (AVG(Value)
For sUser IN ('+ #sUser + ')) As P'
EXEC (#Query)

Try this:
CREATE PROCEDURE YourProcedureName
as
Begin
DECLARE #sUSER AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #sUSER = STUFF((SELECT distinct ',' + QUOTENAME(sUSER) FROM testPIVOT
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
SELECT #query = 'WITH PivotData AS
(
SELECT CID, sUSER, VALUE
FROM dbo.YourTableName
)
SELECT CID, '+ #sUSER +'
FROM PivotData
PIVOT(max(VALUE) FOR sUSER IN('+ #sUSER +')) AS P;';
execute(#query);
End
Hope it could help you!
Thanks.

Related

How to use table variable in SQL Pivot dynamic query

Error: Must declare the table variable "#Temp_FormData".
Query:
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
DECLARE #Temp_FormData TABLE
(
Id UNIQUEIDENTIFIER,
FormId UNIQUEIDENTIFIER,
ContactId UNIQUEIDENTIFIER,
FieldName NVARCHAR(256),
FieldValue NVARCHAR(MAX),
Created DATETIME
)
;WITH TBL AS(
SELECT fe.Id, fe.FormId, fe.ContactId, fd.FieldName, fd.FieldValue, fe.Created
FROM FormEntries fe (NOLOCK)
LEFT JOIN FieldData fd (NOLOCK) ON fd.FormId = fe.Id
)
INSERT INTO #Temp_FormData
SELECT * FROM TBL
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(FieldName)
FROM #Temp_FormData
GROUP BY FieldName
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = N'SELECT ' + #cols + N' FROM
(
SELECT FieldValue, FieldName
FROM #Temp_FormData /* Error here. Tried enclosing variable in square brackets*/
) x
PIVOT
(
MAX(FieldValue)
FOR FieldName in (' + #cols + N')
) p'
EXEC sp_executesql #query
If I execute select * from #Temp_FormData this is the result:
Id
FormId
ContactId
FieldName
FieldValue
Created
1
100
null
Name
John
2023-01-26
1
100
null
Age
25
2023-01-26
2
200
5001
Name
Peter
2023-01-20
2
200
5001
Age
30
2023-01-20
Expected Output:
Id
FormId
ContactId
Name
Age
Created
1
100
null
John
25
2023-01-26
2
200
5001
Peter
30
2023-01-20

how to convert Row to column dynamically in sql server

Here is my tables structure
Result
id ResultId CategoryId Total Attempted Score
----------------------------------------------------
1 8 1 30 25 20
2 8 2 30 30 19
3 8 3 30 27 21
4 7 1 20 15 10
5 7 2 20 20 15
Category
Id CategoryName
-----------------------
1 General
2 Aptitude
3 Technical
I want data in the below format
For ResultId = 8
Id General Aptitude Technical Total
--------------------------------------------------
8 20 19 21 60
For ResultId = 7
Id General Aptitude Total
-------------------------------------
7 10 15 25
I need a help to fetch the data in above format.
NOTE: The final fetched data contains score from Result table but having a column names from category table and according to CategoryId in Result table. Column name will be dynamic
Tried the below code (just for testing) but didn't work
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME(CategoryName)
FROM ( SELECT DISTINCT CategoryName
FROM [dbo].[Category] c) AS PivotExample
SET #SQLQuery =
N'SELECT DISTINCT ' + #PivotColumns + '
FROM [dbo].[Category] c
PIVOT( SUM(c.Id)
FOR CategoryName IN (' + #PivotColumns + ')) AS P'
EXEC sp_executesql #SQLQuery
My query will give you the expected output. You can check the output in SQL Fiddle
--dynamic with case
DECLARE #Sql NVARCHAR(4000) = NULL
DECLARE #ColumnHeaders NVARCHAR(4000);
SET #ColumnHeaders = STUFF((
SELECT DISTINCT ',' + 'Max(CASE WHEN rn =' + quotename(rn, '''') + ' THEN Score else null end ) as ' + CategoryName + CHAR(10) + CHAR(13)
FROM (
SELECT CategoryName, row_number() OVER (ORDER BY CategoryName) rn
FROM ( SELECT DISTINCT CategoryName FROM Category) t0
) t1
FOR XML PATH('')
,TYPE
).value('.', 'varchar(max)'), 1, 1, '');
--print #ColumnHeaders
SET #sql = N' ;with cte as (
select * , Row_number() Over(Partition by ResultId Order by ResultId ) rn from
Result)
Select ResultId, ' + #ColumnHeaders + ', SUM(Score) Total from cte Group by
ResultId ';
EXECUTE sp_executesql #sql

SQL Server 2016 Pivot

I have one question regarding sql (MS SQL 2016) and pivot functionality.
First let me explain about the data structure.
Examples of tbl_Preise. There are several prices (Preis) for each area (Gebiet_von, Gebiet_bis) in relays (StaffelNr). All connected to the same freight (Fracht_id). There can be a different number of relays for each freight. All of these relays repeat for each area, so i.e. there is one price for relay 1 in area 1800 - 1899, but there is another price for relay 1 for area 1900 - 1999.
This is how the table tbl_Preise looks:
autoID Fracht_id Gebiet_von Gebiet_bis Zielland_Nr StaffelNr Preis Mindestpreis Mautkosten
16933 4 1800 1899 4 1 22,6481 0,00 0,00
16934 4 1800 1899 4 2 37,0843 0,00 0,00
16935 4 1800 1899 4 3 54,9713 0,00 0,00
16936 4 1900 1999 4 1 23,4062 0,00 0,00
16937 4 1900 1999 4 2 84,4444 0,00 0,00
Now I have another table tbl_Fracht_Staffeln where the quantity of the relay is saved.
This table looks like:
id fracht_id staffelNr menge
18 4 1 50
19 4 2 100
20 4 3 150
21 4 4 200
Now I want to combine these data, which can vary through different number of relays to each freight.
I have done this via this query:
DECLARE #cols AS NVARCHAR(MAX),#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(staffelNr)
from tbl_Preise (nolock)
where fracht_id = #freightId
group by staffelNr
order by StaffelNr
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'
SELECT
Bezeichnung,
fracht_id,
gebiet_von,
gebiet_bis,
' + #cols + N'
from
(
select
l.Bezeichnung as Bezeichnung,
Zielland_Nr,
tbl_Preise.fracht_id,
gebiet_von,
gebiet_bis,
preis,
tbl_Preise.staffelNr as staffelNr
from
tbl_Preise (nolock)
left join
[dbo].[vw_Laender] l on tbl_Preise.Zielland_Nr = l.[Nummer]
where
tbl_Preise.Fracht_id = ' + cast(#freightId as nvarchar(100)) + '
) x
pivot
(
max(preis)
for staffelNr in (' + #cols + N')
) p
order by
gebiet_von, gebiet_bis'
exec sp_executesql #query;
This query gives me this result:
Bezeichnung fracht_id gebiet_von gebiet_bis 1 2 3 4 5 6
Germany 4 01800 01899 NULL NULL NULL NULL NULL NULL
Germany 4 06400 06499 NULL NULL NULL NULL NULL NULL
Germany 4 1800 1899 22,6481 37,0843 54,9713 64,4062 84,4444 94,6546
Germany 4 20500 20599 17,9088 27,3983 40,8845 46,7485 61,4905 67,835
Germany 4 21200 21299 17,9088 27,3983 40,8845 46,7485 61,4905 67,835
Germany 4 21500 21599 17,9088 27,3983 40,8845 46,7485 61,4905 67,835
Don't look exactly on the prices and the area codes. I've changed some in my example of tbl_Preise to make the relation and sense more clear.
So far so good. But now, as you can see, I have the staffelNr (1,2,3,4,...) as Header in my table.
I need there the column menge of table tbl_Fracht_Staffeln instead.
I tried already some joins and other stuff, but all did not work, because I have found no way to connect the column names (1,2,3,4...) to the table tbl_Fracht_Staffeln. Is there any way to achieve this?
Thank you very much in advance for help!
To do this you need to play with column header 2 times -
DECLARE #cols AS NVARCHAR(MAX),#query AS NVARCHAR(MAX) , #freightId as int , #cols1 AS NVARCHAR(MAX)
select #freightId = 4
select #cols = STUFF((SELECT ',' + QUOTENAME(t1.staffelNr) + ' as ' + QUOTENAME(t2.menge )
from tbl_Preise t1 (nolock)
join tbl_Fracht_Staffeln t2(nolock)
on t1.fracht_id = t2.fracht_id and t1.staffelNr = t2.staffelNr
where t1.fracht_id = #freightId
group by t1.staffelNr , t2.menge
order by t1.StaffelNr
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #cols1 = STUFF((SELECT ',' + QUOTENAME(staffelNr)
from tbl_Preise (nolock)
where fracht_id = #freightId
group by staffelNr
order by StaffelNr
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'
SELECT
fracht_id,
gebiet_von,
gebiet_bis,
' + #cols + N'
from
(
select
Zielland_Nr,
tbl_Preise.fracht_id,
gebiet_von,
gebiet_bis,
preis,
tbl_Preise.staffelNr as staffelNr
from
tbl_Preise (nolock)
where
tbl_Preise.Fracht_id = ' + cast(#freightId as nvarchar(100)) + '
) x
pivot
(
max(preis)
for staffelNr in (' + #cols1 + N')
) p
order by
gebiet_von, gebiet_bis'
print #query
exec sp_executesql #query;

How to pivot the given structure to expected one?

I have queries results as in the image, similarly for 90 date's, so how to group object and make date's as columns and count to respective date's.
Thanks in advance!!
You can do it using a dynamic crosstab:
SQL Fiddle
DECLARE #sql1 VARCHAR(4000) = ''
DECLARE #sql2 VARCHAR(4000) = ''
DECLARE #sql3 VARCHAR(4000) = ''
SELECT #sql1 =
'SELECT
[Object]' + CHAR(10)
SELECT #sql2 = #sql2 +
' , MAX(CASE WHEN [Date] = CAST(''' + CONVERT(VARCHAR(8), [Date], 112) + ''' AS DATE) THEN [count] END) AS ' + QUOTENAME([Date]) + CHAR(10)
FROM(
SELECT DISTINCT [Date] FROM tbl
)t
ORDER BY [Date]
SELECT #sql3 =
'FROM tbl
GROUP BY [Object]
ORDER BY [Object]'
PRINT(#sql1 + #sql2 + #sql3)
EXEC (#sql1 + #sql2 + #sql3)
RESULT
| Object | 2015-01-01 | 2015-01-02 |
|--------|------------|------------|
| 1 | 10 | 34 |
| 2 | 20 | 46 |
| 3 | 130 | 78 |
| 4 | 40 | 89 |
| 5 | 55 | 45 |
This is the output of the PRINT command:
SELECT
[Object]
, MAX(CASE WHEN [Date] = CAST('20150101' AS DATE) THEN [count] END) AS [2015-01-01]
, MAX(CASE WHEN [Date] = CAST('20150102' AS DATE) THEN [count] END) AS [2015-01-02]
FROM tbl
GROUP BY [Object]
ORDER BY [Object]
You can use SQL Server PIVOT relational operator
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
--Get unique values of pivot column
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME([Date])
FROM (SELECT DISTINCT [Date] FROM [dbo].[PivotExample]) AS PivotExample
--Create the dynamic query with all the values for
--pivot column at runtime
SET #SQLQuery =
N'SELECT ObjectId, ' + #PivotColumns + '
FROM [dbo].[PivotExample]
PIVOT( SUM(COUNT)
FOR [Date] IN (' + #PivotColumns + ')) AS P'
EXEC sp_executesql #SQLQuery

SQL CROSS TAB & PIVOT

I am using the following query to retrieve some results
SELECT CONVERT(varchar, TS.StaffID) + CHAR(13)
+ SUBSTRING ( TS.GivenName, 1 , 1 ) + '.' + CHAR(13)
+ TS.Surname AS EmployeeInfo, SH.Hours,ts.UnitID,sh.RowID
FROM dbo.tbl_TimesheetStaff AS TS
Left OUTER JOIN
dbo.tbl_StaffHours AS SH ON
SH.ActivityUnitID = TS.ActivityUnitID
AND Sh.StaffID=ts.StaffID
WHERE TS.UnitID=1
The resulting set looks like
EmployeeInfo Hours UnitID RowID
114 H. Bar 73.71 111 401
114 H. Bar 42.44 111 402
115 M. Cha 20.39 111 401
115 M. Cha 3.616 111 402
116 Q. Xyz 20.39 111 401
116 Q. Xyz 3.61 111 402
Now what I want is to convert the EmployeeInfo column values to column names
114 H. Bar 115 M. Cha 116 Q. Xyz RowID
73.71 20.39 20.39 401
42.44 3.616 3.61 402
The number of rows in EmployeeInfo can vary and hence I need a dynamic pivot function.
Any clues..?
try this:
create table #t table(EmployeeInfo varchar(20), Hours float, UnitID int, RowID int)
insert into #t
SELECT CONVERT(varchar, TS.StaffID) + CHAR(13)
+ SUBSTRING ( TS.GivenName, 1 , 1 ) + '.' + CHAR(13)
+ TS.Surname AS EmployeeInfo, SH.Hours,ts.UnitID,sh.RowID
FROM dbo.tbl_TimesheetStaff AS TS
Left OUTER JOIN
dbo.tbl_StaffHours AS SH ON
SH.ActivityUnitID = TS.ActivityUnitID
AND Sh.StaffID=ts.StaffID
WHERE TS.UnitID=1
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(EmployeeInfo)
from #t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT RowID, ' + #cols + '
from #t
pivot
(
MAX([Hours])
for Code in (' + #cols + ')
) p '
print(#query)
execute(#query)