Select 非空列作为来自动态 sql 的逗号分隔字符串

Select not null columns as a comma separated string from dynamic sql

我尽量避免使用游标。 nvarchar 变量中有一个逗号分隔的列列表,如下所示:

@columnList = 'col1,col2,col5'

有一个 table 有很多 varchar 列:

myTable: [col1],[col2],[col3],[col4],[col5],[col6],[col7]

这就是我 select 使用动态数据的方式 sql:

exec ('select ' + @columnList + ' from myTable')

本次查询returns结果如下:

[col1], [col2] , [col5]
 null , "txt1" ,  null
"txt2",  null  ,  null
 null , "txt3" , "txt4"

这是我需要得到的:

@resultList = "txt1,txt2,txt3,txt4"

如何 select 逗号分隔的字符串只包含非空值?我知道如何将 table 转换为逗号分隔的字符串,所以得到类似的东西:

 [column]
  "txt1"
  "txt2"
  "txt3"
  "txt4"

也可以。有什么建议么?随意提出一个基本方法,我不希望你为我编写实际代码。

您可以使用如下解决方案,仅使用 REPLACE 创建 SQL 查询:

DECLARE @columnList VARCHAR(100)
SET @columnList = 'col1,col2,col5'
SET @columnList = REPLACE(@columnList, ',', ' AS colName FROM myTable UNION ALL SELECT ');

EXEC('SELECT * FROM (SELECT ' + @columnList + ' AS colName FROM myTable)t WHERE NOT t.colName IS NULL');

您还可以使用 UNPIVOT 的解决方案:

DECLARE @columnList VARCHAR(100);
SET @columnList = 'col1,col2,col5';

EXEC('SELECT colName FROM (SELECT ' + @columnList + ' FROM myTable) t1 UNPIVOT (colName FOR columnNames IN (' + @columnList + ')) AS t2');

demo on dbfiddle.uk

既然你提到你已经知道如何聚合成逗号分隔的,下面是如何使用交叉应用取消你的 table:

select unpivoted.*
from myTable
cross apply
( values
     ('col1',col2)
    ,('col2',col2)
    ,('col3',col3) -- etc
)unpivoted(colname,colval)

这适用于 SQL Server 2017,在早期版本 STRING_AGG 上,用法应替换为 XML-based solution

您可以先将结果连接成一行,然后使用 STRING_AGG 将它们聚合成一个字符串:

;with t as
(
SELECT * FROM (VALUES
   (null  , 'txt1' ,  null),
   ('txt2',  null  ,  null),
   (null  , 'txt3' , 'txt4')) x(col1, col2, col5) 
)
SELECT STRING_AGG(STUFF(CONCAT(',' + col1, ',' + col2, ',' + col5), 1, 1, ''), ',')
  FROM t

CTE只是为了展示,你可以直接在你的动态查询中做:

DECLARE @columnList NVARCHAR(MAX) = 'col1,col2,col5'
DECLARE @query NVARCHAR(MAX) = ''
SELECT @query = 'SELECT STRING_AGG(STUFF(CONCAT('','' + ' + REPLACE(@columnList, ',', ', '','' + ') + '), 1, 1, ''''), '','') from mytable'

EXEC sp_executesql @query

Working example on dbfiddle