SQL Pivot possible for this data set? - sql

I trying to write a query and I need some help.
I have some data that looks like this:
However, the end users would like a Pivot so that the data displays like this:
I wrote this code:
SELECT *
FROM
(
SELECT TOP 100
Log0.sn
,CONVERT(VARCHAR(50), Log0.capture_time) AS Instant
,CONVERT(VARCHAR(50),Log0.address) + '/' + Log0.[Key] AS 'Address/Key'
,Log0.average AS Command
,Log1.average AS Actual
FROM ih3_fan_speed_log_0 Log0
LEFT JOIN ih3_fan_speed_log_01 Log1 ON Log0.sn = Log1.sn AND
Log0.capture_time = Log1.capture_time AND Log0.address = Log1.address
WHERE Log0.sn = 'V300188' AND Log0.capture_time = '03/26/2017 13:05:00'
) Src
pivot
(
MAX(sn)
for Instant in ([1], [2], [3], [4])
) piv;
But that returns:
My questions are:
1) Why doesn't my Pivot work ?
2) Is it even possible to do what I need with a Pivot ?
Thanks for any help.
Per request, here is the data:
sn Instant Address/Key Command Actual
V300188 Mar 26 2017 1:05PM 1/EF-1 99.23 99.24
V300188 Mar 26 2017 1:05PM 2/EF-2 99.02 99.04
V300188 Mar 26 2017 1:05PM 3/EF-3 100 0
V300188 Mar 26 2017 1:05PM 4/EF-4 100 100
V300188 Mar 26 2017 1:05PM 41/MUA-1 74.58 74.58
V300188 Mar 26 2017 1:05PM 51/0-10VDC 74.58 74.58
Here is the result set:
Address/Key Command Actual 1 2 3 4
1/EF-1 99.23 99.24 NULL NULL NULL NULL
2/EF-2 99.02 99.04 NULL NULL NULL NULL
3/EF-3 100 0 NULL NULL NULL NULL
4/EF-4 100 100 NULL NULL NULL NULL
41/MUA-1 74.58 74.58 NULL NULL NULL NULL
51/0-10VDC 74.58 74.58 NULL NULL NULL NULL

Here is how you can leverage a dynamic crosstab to accomplish this type of thing. Jeff Moden has a fantastic article explaining this technique here. http://www.sqlservercentral.com/articles/Crosstab/65048/
if OBJECT_ID('tempdb..#Something') is not null
drop table #Something
create table #Something
(
sn varchar(10)
, Instant datetime
, [Address/Key] varchar(20)
, Command numeric(7,2)
, Actual numeric(7,2)
)
insert #Something
select 'V300188', 'Mar 26 2017 1:05PM', '1/EF-1', 99.23, 99.24 union all
select 'V300188', 'Mar 26 2017 1:05PM', '2/EF-2', 99.02, 99.04 union all
select 'V300188', 'Mar 26 2017 1:05PM', '3/EF-3', 100, 0 union all
select 'V300188', 'Mar 26 2017 1:05PM', '4/EF-4', 100, 100 union all
select 'V300188', 'Mar 26 2017 1:05PM', '41/MUA-1', 74.58, 74.58 union all
select 'V300188', 'Mar 26 2017 1:05PM', '51/0-10VDC', 74.58,74.58
declare #MaxCols int
declare #StaticPortion nvarchar(2000) =
'with OrderedResults as
(
select *, ROW_NUMBER() over(partition by sn order by instant) as RowNum
from #Something
)
select sn, instant';
declare #DynamicPortion nvarchar(max) = '';
declare #FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by sn, instant order by sn';
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select #DynamicPortion = #DynamicPortion +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then [Address/Key] end) as address' + CAST(N as varchar(6)) + CHAR(10) +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then Command end) as Command' + CAST(N as varchar(6)) + CHAR(10) +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then Actual end) as Actual' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <=
(
select top 1 Count(*)
from #Something
group by sn, instant
order by COUNT(*) desc
)
select #StaticPortion + #DynamicPortion + #FinalStaticPortion
declare #SqlToExecute nvarchar(max) = #StaticPortion + #DynamicPortion + #FinalStaticPortion;
exec sp_executesql #SqlToExecute

Another Option for a Dynamic Pivot
The twist was the non-distinct/repeating columns in the final results. As you can see, this was resolved with a simple replace (x3).
Declare #SQL varchar(max) = Stuff((Select Distinct ','+QuoteName(concat('A',ColGrp))
+','+QuoteName(concat('B',ColGrp))
+','+QuoteName(concat('C',ColGrp))
From (Select Distinct ColGrp=Row_Number() over (Partition By sn,Instant Order by [Address/Key]) From YourTable ) A
Order By 1
For XML Path('')),1,1,'')
Select #SQL = '
Select [SN],[Instant],' + replace(replace(replace(#SQL,'[A','[Address/Key]=[A'),'[C','[Actual]=[C'),'[B','[Command]=[B') + '
From (
Select [SN]
,[Instant]
,[Col] = Concat(B.Prefix,RN )
,B.Value
From (Select *,RN=Row_Number() over (Partition By sn,Instant Order by [Address/Key]) From YourTable) A
Cross Apply (values (''A'',[Address/Key])
,(''B'',cast(Command as varchar(25)))
,(''C'',cast(Actual as varchar(25)))
) B (PreFix,Value)
) A
Pivot (max([Value]) For [Col] in (' + #SQL + ') ) p'
--Print #SQL
Exec(#SQL);
Returns
EDIT - If it Helps with the Visualization
The generated SQL Looks like this
Select [SN],[Instant],[Address/Key]=[A1],[Command]=[B1],[Actual]=[C1],[Address/Key]=[A2],[Command]=[B2],[Actual]=[C2],[Address/Key]=[A3],[Command]=[B3],[Actual]=[C3],[Address/Key]=[A4],[Command]=[B4],[Actual]=[C4],[Address/Key]=[A5],[Command]=[B5],[Actual]=[C5],[Address/Key]=[A6],[Command]=[B6],[Actual]=[C6]
From (
Select [SN]
,[Instant]
,[Col] = Concat(B.Prefix,RN )
,B.Value
From (Select *,RN=Row_Number() over (Partition By sn,Instant Order by [Address/Key]) From YourTable) A
Cross Apply (values ('A',[Address/Key])
,('B',cast(Command as varchar(25)))
,('C',cast(Actual as varchar(25)))
) B (PreFix,Value)
) A
Pivot (max([Value]) For [Col] in ([A1],[B1],[C1],[A2],[B2],[C2],[A3],[B3],[C3],[A4],[B4],[C4],[A5],[B5],[C5],[A6],[B6],[C6]) ) p

Related

How to filter a pivoted query to bring the records that has at least one count in a specific date range

Now, I have a pivoted query that will bring a set of events that took place on all the towns registered in a table and a date range.
This is my query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
CREATE TABLE #tempDates
(
[FechaSt] Datetime
);
;WITH cte1 (S) AS (
SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (S)
),
cte2 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte1 AS cte2),
cte3 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte2 AS cte2)
INSERT INTO #tempDates
SELECT
[Result] AS [Fecha]
FROM
(
SELECT
DISTINCT CAST([Result] AS DATE) [Result] FROM
(
SELECT
TOP (DATEDIFF(day, #f1, #f2) + 1)
[Result] = DATEADD(day, ROW_NUMBER() OVER(ORDER BY S) - 1, #f1)
FROM cte3
) AS res
) AS [listaFechas];
select #cols =
STUFF
(
(
SELECT
DISTINCT ',' + QUOTENAME(convert(CHAR(10), d.FechaSt, 120))
FROM #tempDates d
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,''
)
SET #query =
'
SELECT
IdMunicipio,
Ciudad,
Region,
Base,
' + #cols + '
FROM
(
SELECT
[Jc].[ID],
[Jc].[IdMunicipio],
[Wc].[Ciudad],
[Wr].[Region],
IIF
(
[Mk].[EsBase] = 1,
''<i class="fas fa-star fa-fw textoAmarilloSm"></i>'',
''''
) AS [Base],
CAST([Jc].[Fecha] AS date) AS [FechaJc]
FROM [dbo].[Jornadas_Cronograma] [Jc]
INNER JOIN
[dbo].[L_MunicipiosCapacitacion] [Mk]
ON [Jc].[IdMunicipio] = [Mk].[ID]
INNER JOIN
[dbo].[L_RegionesMundo] [Wr]
ON [Mk].[RegionId] = [Wr].[RegionID]
INNER JOIN
[dbo].[L_CiudadesMundo] [Wc]
ON [Mk].[CiudadId] = [Wc].[CityID]
) X
PIVOT
(
COUNT([ID])
FOR [FechaJc] IN (' + #cols + ')
) pvt
ORDER BY Ciudad ASC
'
execute(#query);
So, according to the specified date range (#f1 and #f2), I'm creating a temp table that stores all the dates within that range, to stuff that data afterwards to achive the pivot.
This is a sample of the data returned:
IdMunicipio | Ciudad | ... | 2022-10-02 | 2022-10-03 | 2022-10-04
1 | Bogotá | ... | 0 | 1 | 3
2 | Cali | ... | 0 | 12 | 3
3 | Medell.| ... | 0 | 0 | 0
4 | Buga | ... | 0 | 10 | 0
5 | Chía | ... | 0 | 0 | 0
6 | Cota | ... | 0 | 0 | 0
7 | Cajicá | ... | 0 | 0 | 2
What I need is to filter this query, so that it will only bring the towns that had at least 1 event within the date range, for this example it will be:
IdMunicipio | Ciudad | ... | 2022-10-02 | 2022-10-03 | 2022-10-04
1 | Bogotá | ... | 0 | 1 | 3
2 | Cali | ... | 0 | 12 | 3
4 | Buga | ... | 0 | 10 | 0
7 | Cajicá | ... | 0 | 0 | 2
What I have tryed:
DROP TABLE #tempDates
DECLARE #f1 datetime = '2022-10-02';
DECLARE #f2 datetime = '2022-10-08';
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
CREATE TABLE #tempDates
(
[FechaSt] Datetime
);
;WITH cte1 (S) AS (
SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) n (S)
),
cte2 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte1 AS cte2),
cte3 (S) AS (SELECT 1 FROM cte1 AS cte1 CROSS JOIN cte2 AS cte2)
INSERT INTO #tempDates
SELECT
[Result] AS [Fecha]
FROM
(
SELECT
DISTINCT CAST([Result] AS DATE) [Result] FROM
(
SELECT
TOP (DATEDIFF(day, #f1, #f2) + 1)
[Result] = DATEADD(day, ROW_NUMBER() OVER(ORDER BY S) - 1, #f1)
FROM cte3
) AS res
) AS [listaFechas];
select #cols =
STUFF
(
(
SELECT
DISTINCT ',' + QUOTENAME(convert(CHAR(10), d.FechaSt, 120))
FROM #tempDates d
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,''
)
SET #query =
'
SELECT
IdMunicipio,
Ciudad,
Region,
Base,
' + #cols + '
FROM
(
SELECT
[Jc].[ID],
[Jc].[IdMunicipio],
[Wc].[Ciudad],
[Wr].[Region],
IIF
(
[Mk].[EsBase] = 1,
''<i class="fas fa-star fa-fw textoAmarilloSm"></i>'',
''''
) AS [Base],
CAST([Jc].[Fecha] AS date) AS [FechaJc]
FROM [dbo].[Jornadas_Cronograma] [Jc]
INNER JOIN
[dbo].[L_MunicipiosCapacitacion] [Mk]
ON [Jc].[IdMunicipio] = [Mk].[ID]
INNER JOIN
[dbo].[L_RegionesMundo] [Wr]
ON [Mk].[RegionId] = [Wr].[RegionID]
INNER JOIN
[dbo].[L_CiudadesMundo] [Wc]
ON [Mk].[CiudadId] = [Wc].[CityID]
WHERE
(
(
SELECT
COUNT(*)
FROM [dbo].[Jornadas_Cronograma] [Jb]
WHERE
(CAST([Jb].[Fecha] as date) BETWEEN ' + CAST(#f1 as date) + ' AND ' + CAST(#f2 as date) + ')
)
) > 0;
) X
PIVOT
(
COUNT([ID])
FOR [FechaJc] IN (' + #cols + ')
) pvt
ORDER BY Ciudad ASC
'
execute(#query);
But this will break into an error:
Msg 402, Level 16, State 1, Line 92
The data types nvarchar(max) and date are incompatible in the add operator.
This is breaking in the line where I declare the WHERE Clause:
(CAST([Jb].[Fecha] as date) BETWEEN ' + CAST(#f1 as date) + ' AND ' + CAST(#f2 as date) + ')
I've thinked that maybe if a somehow SUM the results for the dates columns, I will be able to filter where that sum is > 0, but I'm not being able to solve the syntax.

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

How to pivot a table this way when there are 3000 columns

I am using SQL Server
I have a table TT that looks like this
TargetID RowID Actual
0001 1 0
0001 2 1
0001 3 1
0002 1 0
0002 2 1
0002 3 0
0003 1 1
0003 2 1
0003 3 0
How can I pivot it is to this
RowID Target0001 Target0002 Target0003
1 0 0 1
2 1 1 1
3 1 0 0
I tried
SELECT 'TargetID' + TargetID, RowID, Actual
FROM TT
WHERE TargetID = '0001'
UNION ALL
SELECT 'TargetID' + TargetID, RowID, Actual
FROM TT
WHERE TargetID = '0002'
SELECT 'TargetID' + TargetID, RowID, Actual
FROM TT
WHERE TargetID = '0003'
But there are 3000 TargetIDs and my method is not good for that
Any idea how to do that?
You can try this...
DECLARE #ColumnsTable TABLE ([ColumnName] VARCHAR(50));
INSERT INTO #ColumnsTable ([ColumnName])
SELECT DISTINCT '[' + CONVERT(VARCHAR(48), [TargetID]) + ']'
FROM TT;
DECLARE #PivotColumns VARCHAR(MAX), #TotalColumn VARCHAR(MAX), #SQL VARCHAR(MAX);
SET #PivotColumns = (SELECT STUFF((SELECT DISTINCT ', ' + CONVERT(VARCHAR(50), [ColumnName])
FROM #ColumnsTable
FOR XML PATH('')), 1, 2, ''));
SET #SQL = 'SELECT RowID,' +#PivotColumns +'
FROM (
SELECT RowID,TargetID,Actual
FROM TT) AS t
PIVOT (MAX([Actual])
FOR [TargetID] IN (' + #PivotColumns + ')) AS p';
EXEC(#SQL);

How to transform rows into column in SQL Server?

Using MS SQL Server and I have below table:
+-----------+------------------+------------------+---------------------+-------------------------+
| SrNo | ApprCode | ApprName | ApprStatus | ApprDate |
+-----------+------------------+------------------+---------------------+-------------------------+
| SR_176 | X001 | James | APR | 2019-10-03 |
| SR_176 | X002 | Sam | APR | 2019-10-03 |
+-----------+------------------+------------------+---------------------+-------------------------+
Tried with PIVOT but its showing james and X001 as a column heading:
Expected Result:
+-----------+-------------- +---------------+---------------------+-------------------------+------------------+
SrNo | ApprCode_1 | ApprName_1 | ApprDate_2 ApprCode_2 ApprName_2 ApprDate_2
+-----------+---------------+---------------+---------------------+-------------------------+------------------+
SR_176 X001 James 2019-10-03 X002 Sam 2019-10-03
+-----------+---------------+---------------+---------------------+---- ---------------------+------------------+
Query to generate data:
CREATE TABLE #Temp
(
SrNo NVARCHAR(200),
ApprCode NVARCHAR(200),
ApprName NVARCHAR(200),
ApprDate Date
)
INSERT INTO #Temp VALUES ('SR_176','X001','James', '2019-10-03')
INSERT INTO #Temp VALUES ('SR_176','X002','Sam', '2019-10-03')
Query that I tried:
declare #sql nvarchar(max)
declare #name_concat nvarchar(max)
declare #name1_concat nvarchar(max)
declare #select_aggs nvarchar(max)
select #name_concat = STUFF((select distinct ',' + quotename(ApprCode) from #Temp order by 1 for xml path('')), 1, 1, '')
select #name1_concat = STUFF((select distinct ',' + quotename(ApprName) from #Temp order by 1 for xml path('')), 1, 1, '')
select #sql = '
;with cte2 as
(
SELECT SrNo,' + #name_concat + ',' + #name1_concat + '
FROM #Temp
PIVOT(MAX(ApprCode)
FOR ApprCode IN (' + #name_concat + ')) AS PVTTable PIVOT
(
MAX(ApprName)
FOR ApprName IN (' + #name1_concat + ')) AS PVTTable1
)
select * from cte2
'
exec sp_executesql #sql
In fact, This is not a SQL Pivot situation and the sample data for question is not enough to test it completely but you can find the main idea :
Select
SrNo,
MAX(IIF(ApprCode = 'X001', ApprCode, null)) as ApprCode_1,
MAX(IIF(ApprCode = 'X001', ApprName, null)) as ApprName_1,
MAX(IIF(ApprCode = 'X001', ApprDate, null)) as ApprDate_1,
MAX(IIF(ApprCode = 'X002', ApprCode, null)) as ApprCode_2,
MAX(IIF(ApprCode = 'X002', ApprName, null)) as ApprName_2,
MAX(IIF(ApprCode = 'X002', ApprDate, null)) as ApprDate_2
From #Temp
Group by SrNo
This code works if ApprCode was the key to make two separate columns & SrNo is for the group by between rows.
I solved it by using ROW_NUMBER() and Case Expression:
Here is the query:
SELECT *,
Row_number()
OVER(
partition BY srno
ORDER BY apprdate) AS RN
INTO #temptable
FROM #temp
SELECT srno,
CASE rn
WHEN 1 THEN Max(apprname)
END AS [1 Approver],
CASE rn
WHEN 2 THEN Max(apprname)
END AS [2 Approver],
CASE rn
WHEN 1 THEN Max(apprcode)
END AS [1 ApproverCode],
CASE rn
WHEN 2 THEN Max(apprcode)
END AS [2 ApproverCode],
CASE rn
WHEN 1 THEN Max(apprdate)
END AS [1 Date],
CASE rn
WHEN 2 THEN Max(apprdate)
END AS [2 Date]
INTO #james
FROM #temptable
GROUP BY srno,
rn
SELECT srno,
Max([1 approver]) AS ApproverName_1,
Max([1 approvercode]) AS ApproverCode_1,
Max([1 date]) AS ApproverDate_1,
Max([2 approver]) AS ApproverName_2,
Max([2 approvercode]) AS ApproverCode_2,
Max([2 date]) AS ApproverDate_2
FROM #james
GROUP BY srno

SQL Server 2008 Management Studio : convert row data into columns [duplicate]

This question already has answers here:
Transpose rows and columns with no aggregate
(2 answers)
Closed 8 years ago.
I have tried viewing other posts on the subject but all the examples I've seen are based on knowing a specific value.
Example of what I have:
Address Name Number
------- ------- -------
1234 Main Bob 555-555-5555
1234 Main Karen 444-444-4444
1990 Maple Susie 333-333-3333
1010 12th Joe 222-222-2222
1010 12th Beth 111-111-1111
1010 12th Steve 444-433-3221
Example of what I want:
Address Contact1 Contact2 Contact3
------- ------- -------- --------
1234 Main Bob:555-555-5555 Karen:444-444-4444 NULL
1990 Maple Susie:333-333-3333 NULL NULL
1010 12th Joe: 222-222-2222 Beth 111-111-1111 Steve 444-433-3221
There are thousands of rows so I can't CASE and.. I'm a more than a little lost here.
Any suggestions?
I think you can use the following query. This assumes you have maximum three contacts
;WITH orderedAddress(Address,Name,Number,Sort)
AS
(
SELECT Address,Name,Number,ROW_NUMBER() OVER(PARTITION BY Address ORDER BY Name) AS num
FROM Addresses
)
SELECT main.Address,Contact1.Name + ':' + Contact1.Number AS Contact1 ,
Contact2.Name + ':' + ISNULL(Contact2.Number,'') AS Contact2 ,
Contact3.Name + ':' + ISNULL(Contact3.Number,'') AS Contact3
FROM
(SELECT DISTINCT Address FROM Addresses) AS main
LEFT JOIN OrderedAddress Contact1 ON main.Address = Contact1.Address AND Contact1.Sort=1
LEFT JOIN OrderedAddress Contact2 ON main.Address = Contact2.Address AND Contact2.Sort=2
LEFT JOIN OrderedAddress Contact3 ON main.Address = Contact3.Address AND Contact3.Sort=3
A dynamic pivot will work but so will a dynamic cross tab. Generally speaking a cross tab will beat the pivot for performance. Here is an example of one I posted just a few days ago.
if OBJECT_ID('Something') is not null
drop table Something
create table Something
(
ID int,
Subject1 varchar(50)
)
insert Something
select 10868952, 'NUR/3110/D507' union all
select 10868952, 'NUR/3110/D512' union all
select 10868952, 'NUR/4010/D523' union all
select 10868952, 'NUR/4010/HD20' union all
select 12345, 'asdfasdf'
declare #MaxCols int
declare #StaticPortion nvarchar(2000) =
'with OrderedResults as
(
select *, ROW_NUMBER() over(partition by ID order by Subject1) as RowNum
from Something
)
select ID';
declare #DynamicPortion nvarchar(max) = '';
declare #FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by ID order by ID';
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select #DynamicPortion = #DynamicPortion +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then Subject1 end) as Subject' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <=
(
select top 1 Count(*)
from Something
group by ID
order by COUNT(*) desc
)
select #StaticPortion + #DynamicPortion + #FinalStaticPortion
declare #SqlToExecute nvarchar(max) = #StaticPortion + #DynamicPortion + #FinalStaticPortion;
exec sp_executesql #SqlToExecute