No sé si esto es más rápido, pero podrías usar un truco:FOR XML AUTO omitirá columnas sin contenido:
DECLARE @tbl TABLE(col1 INT,col2 INT,col3 INT);
INSERT INTO @tbl VALUES (1,2,NULL),(1,NULL,NULL),(NULL,NULL,NULL);
SELECT *
FROM @tbl AS tbl
FOR XML AUTO
Este es el resultado:col3 falta...
<tbl col1="1" col2="2" />
<tbl col1="1" />
<tbl />
Sabiendo esto, puede encontrar la lista de columnas, que no son NULL en todas las filas, así:
DECLARE @ColList VARCHAR(MAX)=
STUFF
(
(
SELECT DISTINCT ',' + Attr.value('local-name(.)','nvarchar(max)')
FROM
(
SELECT
(
SELECT *
FROM @tbl AS tbl
FOR XML AUTO,TYPE
) AS TheXML
) AS t
CROSS APPLY t.TheXML.nodes('/tbl/@*') AS A(Attr)
FOR XML PATH('')
),1,1,''
);
SELECT @ColList
El contenido de @ColList ahora es col1,col2 . Esta cadena se puede colocar en un SELECT creado dinámicamente .
ACTUALIZACIÓN:Sugerencias
Sería muy inteligente reemplazar el SELECT * con una lista de columnas creada a partir de INFORMATION_SCHEMA.COLUMNS excluyendo todos los no anulables . Y, si es necesario y posible, tipos que contienen datos muy grandes (BLOB).
ACTUALIZACIÓN 2:Rendimiento
No sé cuáles son sus datos muy grandes significa en realidad ... Acabo de probar esto en una tabla con alrededor de 500.000 filas (con SELECT * ) y volvió correctamente después de menos de un minuto. Espero que esto sea lo suficientemente rápido...