Lol, I was working on dynamic name code "just in case", and was gonna post it as an example anyway. Just expand the #results table to include however many max names you will need.
Edit: This code initially assumes there's an id / datetime you need if you want to get the names out in the same order they were encountered. If not, if, for example, you want the names in alpha order (which I would, with that many names) just let me know and I will adjust the code accordingly:
Basically, chanage this:
INSERT INTO #results_columns
SELECT ROW_NUMBER() OVER(ORDER BY MIN(id)), NAME
FROM #data
GROUP BY NAME;
to this:
INSERT INTO #results_columns
SELECT ROW_NUMBER() OVER(ORDER BY NAME), NAME
FROM #data
GROUP BY NAME;
DROP TABLE IF EXISTS #data;
CREATE TABLE #data (
ID int IDENTITY(1, 1) NOT NULL,
TYPE varchar(10) NOT NULL,
NAME varchar(50) NOT NULL,
AMT decimal(9, 2) NOT NULL
);
INSERT INTO #data VALUES
('A','JOHN',500),
('A','MARY',325),
('A','BILL',650),
('A','FRED',321),
('A','???',999),
('B','JOHN',405),
('B','MARY',218),
('B','BILL',945),
('B','FRED',735),
('C','JOHN',800),
('C','MARY',420),
('C','BILL',675),
('C','FRED',380);
DROP TABLE IF EXISTS #results;
CREATE TABLE #results (
TYPE varchar(10) NOT NULL PRIMARY KEY,
VALUE1 decimal(9, 2) NULL,
VALUE2 decimal(9, 2) NULL,
VALUE3 decimal(9, 2) NULL,
VALUE4 decimal(9, 2) NULL
);
DROP TABLE IF EXISTS #results_columns;
CREATE TABLE #results_columns (
column_number smallint NOT NULL PRIMARY KEY,
name varchar(10) NOT NULL
);
INSERT INTO #results_columns
SELECT ROW_NUMBER() OVER(ORDER BY MIN(id)), NAME
FROM #data
GROUP BY NAME;
DECLARE @COLUMN_NUMBER smallint;
DECLARE @NAME varchar(10);
DECLARE @SQL nvarchar(max);
DECLARE NAME_CURSOR CURSOR LOCAL FAST_FORWARD FOR
SELECT *
FROM #results_columns
ORDER BY column_number
OPEN NAME_CURSOR;
WHILE 1 = 1
BEGIN
FETCH NEXT FROM NAME_CURSOR INTO @COLUMN_NUMBER, @NAME;
IF @@FETCH_STATUS <> 0
BREAK;
IF NOT EXISTS(SELECT * FROM tempdb.sys.columns WHERE object_id = OBJECT_ID('tempdb.dbo.#results') AND name = 'VALUE' + CAST(@COLUMN_NUMBER AS varchar(5)))
BEGIN
PRINT '';
PRINT REPLICATE('!', 40);
RAISERROR('Column "VALUE%i" does not exist in temp table, therefore cannot use name "%s" in final result.', 16, 1, @COLUMN_NUMBER, @NAME);
PRINT REPLICATE('!', 40);
PRINT '';
CONTINUE
END /*IF*/
SET @sql = 'EXEC tempdb.sys.sp_rename ''dbo.#results.VALUE' +
CAST(@COLUMN_NUMBER AS varchar(5)) + ''', ''' + @NAME + ''', ''COLUMN''';
PRINT @sql;
EXEC(@sql);
END /*WHILE*/
INSERT INTO #results
SELECT
d.TYPE,
MAX(CASE WHEN rc.COLUMN_NUMBER = 1 THEN d.AMT END),
MAX(CASE WHEN rc.COLUMN_NUMBER = 2 THEN d.AMT END),
MAX(CASE WHEN rc.COLUMN_NUMBER = 3 THEN d.AMT END),
MAX(CASE WHEN rc.COLUMN_NUMBER = 4 THEN d.AMT END)
FROM #data d
LEFT OUTER JOIN #results_columns rc ON rc.NAME = d.NAME
GROUP BY d.TYPE
SELECT *
FROM #results
ORDER BY TYPE
GO