One potential solution, assuming there is a max of 4 types of operations:
;WITH src AS
(
SELECT JobNum,
rn = ROW_NUMBER() OVER (PARTITION BY JobNum ORDER BY @@SPID),
[H/E] = CONCAT(Operation,' (',Hours,'/',Estimate,')')
FROM dbo.whoknows AS w
)
SELECT JobNum, Operation = COALESCE([1], ''),
Operation = COALESCE([2], ''),
Operation = COALESCE([3], ''),
Operation = COALESCE([4], '')
FROM src PIVOT
(MAX([H/E]) FOR rn IN ([1],[2],[3],[4])) AS p;
Working db<>fiddle example.
If you need it to be smart about adapting to any number of operations, you can build a dynamic PIVOT:
DECLARE @numOps int,
@output nvarchar(max),
@cols nvarchar(max),
@sql nvarchar(max);
SELECT @numOps = COUNT(DISTINCT Operation) FROM dbo.whoknows;
;WITH OpCount AS
(
SELECT rn = QUOTENAME(ROW_NUMBER() OVER (ORDER BY @@SPID))
FROM STRING_SPLIT(REPLICATE(',', @numOps - 1), ',')
)
SELECT @output = STRING_AGG(CONCAT('Operation = COALESCE(',
rn, ', '''')'),',
'), @cols = STRING_AGG(rn, ',') FROM OpCount;
SET @sql = CONCAT(N';WITH src AS
(
SELECT JobNum,
rn = ROW_NUMBER() OVER (PARTITION BY JobNum ORDER BY @@SPID),
[H/E] = CONCAT(Operation,'' ('',Hours,''/'',Estimate,'')'')
FROM dbo.whoknows AS w
)
SELECT JobNum, ', @output, ' FROM src PIVOT
(MAX([H/E]) FOR rn IN (', @cols, ')) AS p;');
EXEC sys.sp_executesql @sql;
Also with a db<>fiddle example.
Output in both cases:
| JobNum |
Operation |
Operation |
Operation |
Operation |
| 1 |
Fabrication (5/6) |
Paint (1/1) |
Packaging (0/1) |
|
| 2 |
Fabrication (6/6) |
Welding (2/4) |
Paint (0/2) |
Packaging (0/1) |
| 3 |
Fabrication (3/2) |
Packaging (0.25/0.5) |
|
|
And finally, for the late-breaking requirement of SQL Server 2014 (<shudder>):
DECLARE @numOps int, @output nvarchar(max),
@sql nvarchar(max), @cols nvarchar(max);
SELECT @numOps = COUNT(DISTINCT Operation) FROM dbo.whoknows;
;WITH OpCount AS (
SELECT r = 1 UNION ALL
SELECT r+1 FROM OpCount WHERE r < @numOps
), ocols AS
(
SELECT c = STUFF((SELECT ','
+ CONCAT('Operation = COALESCE(', QUOTENAME(r), ', '''')')
FROM OpCount ORDER BY r
FOR XML PATH(''), TYPE).value(N'text()[1]', N'nvarchar(max)'),1,1,'')
), pcols AS
(
SELECT c = STUFF((SELECT CONCAT(',',QUOTENAME(r))
FROM OpCount ORDER BY r
FOR XML PATH(''), TYPE).value(N'text()[1]', N'nvarchar(max)'),1,1,'')
)
SELECT @output = (SELECT c FROM ocols),
@cols = (SELECT c FROM pcols)
OPTION (MAXRECURSION 255);
SET @sql = CONCAT(N';WITH src AS (
SELECT JobNum,
rn = ROW_NUMBER() OVER (PARTITION BY JobNum ORDER BY @@SPID),
[H/E] = CONCAT(Operation,'' ('',Hours,''/'',Estimate,'')'')
FROM dbo.whoknows AS w )
SELECT JobNum, ', @output, ' FROM src PIVOT
(MAX([H/E]) FOR rn IN (', @cols, ')) AS p;');
EXEC sys.sp_executesql @sql;
Working example here. That could probably be tidier but old, unsupported versions aren't worth the effort IMHO.
string_aggaround a subquery.SELECT ..., MAX(CASE WHEN RowNum = 3 THEN Operation END) AS Oparation3. (E.g., what @siggemannen just posted.)