Here's a dynamic set I was working on. I'm running out of time so it's not cleaned up, and it determines the dynamic row numbers by the max number of rows in the table as a whole, meaning that if you have any duplicates in any column at all, you'll be left with rows where every single column is null.
But other than that, this should work perfectly fine, and the script contains the necessary info showing you how to concatenate a final "WHERE S1.COLNAME IS NOT NULL AND S2.COLNAME IS NOT NULL AND .." filter to the result table, to eliminate those full-null rows.
Other than that, here's the script. It's gonna be heavy, obviously, so I included a (nolock) hint in it, and a "WHERE ColName is not null" to remove useless results.
Try this on a smaller table and see it work.
/*
Set your table and schema on @MYTABLE and @MYSCHEMA variables.
*/
SET NOCOUNT ON
DECLARE @MYTABLE SYSNAME = 'Mytablename here'
, @MYSCHEMA sysname = 'dbo'
DECLARE @SQL NVARCHAR(MAX) = '', @COLNAME sysname = '', @MYCOLS NVARCHAR(max) = ''
DECLARE @COL_NOW INT = 1, @COL_MAX INT =
(SELECT COUNT(*)
FROM sys.columns
WHERE object_id = (SELECT object_id FROM sys.tables where name = @MYTABLE and SCHEMA_NAME(schema_id) = @MYSCHEMA))
SELECT @COLNAME = name
FROM sys.columns
WHERE column_id = 1
and object_id = (SELECT object_id FROM sys.tables where name = @MYTABLE and SCHEMA_NAME(schema_id) = @MYSCHEMA)
SET @SQL = 'FROM
(SELECT ROW_NUMBER() OVER (ORDER BY '+@COLNAME+' ASC) RN
FROM '+@MYSCHEMA+'.'+@MYTABLE+' (nolock)) S'
WHILE @COL_NOW <= @COL_MAX
BEGIN
SELECT @COLNAME = name
FROM sys.columns
WHERE column_id = @COL_NOW
and object_id = (SELECT object_id FROM sys.tables where name = @MYTABLE and SCHEMA_NAME(schema_id) = @MYSCHEMA)
SELECT @SQL = @SQL+'
FULL JOIN
(SELECT DISTINCT DENSE_RANK() OVER (ORDER BY '+@COLNAME+' ASC) RN, '+@COLNAME+'
FROM '+@MYSCHEMA+'.'+@MYTABLE+' (nolock)
WHERE '+@COLNAME+' IS NOT NULL) S'+CAST(@COL_NOW AS NVARCHAR(25))+' ON S'+CAST(@COL_NOW AS NVARCHAR(25))+'.RN = S.RN'
IF @COL_NOW = 1
SELECT @MYCOLS = @MYCOLS+' S'+CAST(@COL_NOW AS NVARCHAR(25))+'.'+@COLNAME
ELSE
SELECT @MYCOLS = @MYCOLS+', S'+CAST(@COL_NOW AS NVARCHAR(25))+'.'+@COLNAME
SET @COL_NOW = @COL_NOW+1
END
SELECT @SQL = 'SELECT'+@MYCOLS+'
'+@SQL+'
ORDER BY S1.RN ASC';
--PRINT(@SQL); -- To check resulting dynamic SQL without executing it (Warning, print will only show first 8k characters)
EXEC sp_executesql @SQL;
GO