我有一个联结表:
id | warehouse | comp1 | comp2 | comp3 | comp4
----------------------------------------------
1 | w1 | 1 | 0 | 1 | 1 => String: 'col1,col3,col4'
2 | w2 | 1 | 1 | 0 | 1 => String: 'col1,col2,col4'
3 | w3 | 0 | 1 | 0 | 0 => String: 'col2'
可能的解决方案 - 更改联结表
忽略使用列名,只需使用子字符串或掩码
(例如使用like %comp1%
):
id | warehouse| companies
-----------------------------------
1 | w1 | 'comp1,comp3,comp4'
2 | w2 | 'comp3'
3 | w3 | 'comp1,comp2,comp4'
答案 0 :(得分:3)
您需要的内容基本上是排除unpivot
和id
列名称的warehouse
。
这样做的一种方法是在使用for xml path('')
的子查询中使用Table Value Constructor来构建列名称的连接列表。
select T1.id,
T1.warehouse,
stuff((
select ','+T2.company
from (values(T1.comp1, 'comp1'),
(T1.comp2, 'comp2'),
(T1.comp3, 'comp3'),
(T1.comp4, 'comp4')) as T2(value, company)
where T2.value = 1
for xml path('')
), 1, 1, '') as comp
from YourTable as T1
添加新列时,需要修改上述查询。需要动态生成将与动态列数一起使用的查询。您可以使用sys.columns获取列名并动态构建上述查询,并使用execute执行查询。
declare @SQL nvarchar(max)
set @SQL = '
select T1.id,
T1.warehouse,
stuff((
select '',''+T2.company
from (values'+
stuff((
select ',(T1.'+name, ','''+name+''')'
from sys.columns
where object_name(object_id) = 'YourTable' and
name not in ('id', 'warehouse')
for xml path('')
), 1, 1, '') +
') as T2(value, company)
where T2.value = 1
for xml path('''')
), 1, 1, '''') as comp
from YourTable as T1'
exec (@SQL)
当我说这需要动态SQL时,我并不完全真实。在这种情况下,实际上可以通过一些xQuery来解决这个问题。
select id,
warehouse,
stuff((
select ','+T3.N.value('local-name(.)', 'nvarchar(128)')
from T2.X.nodes('*[not(local-name() = ("id","warehouse"))]') as T3(N)
where T3.N.value('(./text())[1] cast as xs:boolean?', 'bit') = 1
for xml path('')
), 1, 1, '') as comp
from YourTable as T1
cross apply (
select T1.*
for xml path(''), type
) as T2(X)
构建逗号分隔列列表与使用for xml path('')
的先前查询中的相同。这里在交叉应用中,为每一行构造了一个XML,用于查询子查询中的值和元素名称。元素名称对应于列名称,可使用local-name(.)
访问。使用nodes()
表达式,一行的值是不重要的(甚至是真正的单词)。 nodes()
还确保id
和warehouse
不会作为列返回。
答案 1 :(得分:0)
用于此的用例。
select case when column1=1 then '1' else '0' end as column1 from tableName