In my thought, the following query will handle your issue. However the SQL Server has column number limit for tables.
Columns per table 1,024 Tables that include sparse column sets
include up to 30,000 columns. See sparse column sets.
You should take this considiration for your data.
DROP TABLE IF EXISTS #Test
DROP TABLE IF EXISTS ##PivotUnlimited
CREATE TABLE #Test(Surname VARCHAR(100) , GivenName VARCHAR(200),
Adress VARCHAR(100),City VARCHAR(100))
INSERT INTO #Test
VALUES
('Name1','Givename1','Addr11','City11'),
('Name1','Givename1','Addr12','City12'),
('Name2','Givename2','Addr21','City21'),
('Name2','Givename2','Addr22','City21'),
('Name2','Givename2','Addr23','City23')
,('Name5','Givename5','Addr51','City51'),
('Name5','Givename5','Addr52','City52'),
('Name5','Givename5','Addr53','City53'),
('Name5','Givename5','Addr54','City54'),
('Name3','Givename3','Addr31','City31')
DECLARE @Counter AS INT=1
DECLARE @Max AS INT
DECLARE @SQL AS VARCHAR(MAX)
SELECT @Max= MAX(DetMax) FROM
(
SELECT ROW_NUMBER() OVER(Partition by Surname ORDER BY Surname ) AS DetMax FROM #Test
) AS TMP
DROP TABLE IF EXISTS ##PivotUnlimited
CREATE TABLE ##PivotUnlimited (Surname VARCHAR(100),GivenName VARCHAR(100))
WHILE @Counter <=@Max
BEGIN
SET @SQL= 'ALTER TABLE ##PivotUnlimited ADD ADDR' + CONVERT(VARCHAR,@Counter) + ' VARCHAR(100)'
EXEC(@SQL)
SET @SQL= 'ALTER TABLE ##PivotUnlimited ADD City' + CONVERT(VARCHAR,@Counter) + ' VARCHAR(100)'
EXEC(@SQL)
SET @Counter=@Counter+1
END
INSERT INTO ##PivotUnlimited (Surname,GivenName)
SELECT DISTINCT Surname , GivenName FROM #Test
DECLARE @Name AS VARCHAR(100)
DECLARE cursorT CURSOR
FOR
SELECT DISTINCT Surname from #test
OPEN cursorT
FETCH NEXT FROM cursorT INTO @Name
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @CounterCursor AS INT=1
DECLARE @MaxCursort AS INT =0
DECLARE @UpdateSQL AS VARCHAR(MAX)
DECLARE @UptAdr AS VARCHAR(100)
DECLARE @UptCity AS VARCHAR(100)
SELECT @MaxCursort=RowNumber FROM (
SELECT ROW_NUMBER() OVER(Partition by Surname ORDER BY Surname ) AS RowNumber FROM #Test
WHERE Surname=@Name
) AS TMP_TBL
WHILE @CounterCursor<= @MaxCursort
BEGIN
SELECT @UptAdr=Adress ,@UptCity=City FROM (
SELECT ROW_NUMBER() OVER(Partition by Surname ORDER BY Surname ) AS RowNumber,* FROM #Test
) AS TMP_TBL WHERE RowNumber=@CounterCursor and Surname=@Name
SET @UpdateSQL= 'UPDATE ##PivotUnlimited SET ADDR' + CONVERT(VARCHAR,@CounterCursor) + ' = ' + '''' + @UptAdr +'''' + ' , '
+ ' City' + CONVERT(VARCHAR,@CounterCursor) + ' = ' + '''' + @UptCity +'''' + ' WHERE Surname = ' + '''' + @Name + ''''
EXEC (@UpdateSQL)
SET @CounterCursor=@CounterCursor+1
END
FETCH NEXT FROM cursorT INTO @Name
END
CLOSE cursorT
DEALLOCATE cursorT
SELECT * FROM ##PivotUnlimited
+---------+-----------+--------+--------+--------+--------+--------+--------+--------+--------+
| Surname | GivenName | ADDR1 | City1 | ADDR2 | City2 | ADDR3 | City3 | ADDR4 | City4 |
+---------+-----------+--------+--------+--------+--------+--------+--------+--------+--------+
| Name1 | Givename1 | Addr11 | City11 | Addr12 | City12 | NULL | NULL | NULL | NULL |
| Name2 | Givename2 | Addr21 | City21 | Addr22 | City21 | Addr23 | City23 | NULL | NULL |
| Name3 | Givename3 | Addr31 | City31 | NULL | NULL | NULL | NULL | NULL | NULL |
| Name5 | Givename5 | Addr51 | City51 | Addr52 | City52 | Addr53 | City53 | Addr54 | City54 |
+---------+-----------+--------+--------+--------+--------+--------+--------+--------+--------+