SQL-当值为1时获取列名

标签 sql sql-server-2008

我有一个连接表:

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'
  • 如果列的值为1,如何获取列名字符串?

可能的解决方案 - 更改连接表

忽略使用列名,仅使用子字符串或掩码 (例如使用 like %comp1%):

id | warehouse| companies
-----------------------------------
1  | w1       | 'comp1,comp3,comp4'
2  | w2       | 'comp3'
3  | w3       | 'comp1,comp2,comp4'

最佳答案

您需要的基本上是对排除 idwarehouse 的列名称进行 unpivot

一种方法是使用 Table Value Constructor在使用 for xml path('') 构建列名称串联列表的子查询中。

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

SQL Fiddle

添加新列时需要修改上面的查询。需要动态生成适用于动态列数的查询。您可以使用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 Fiddle

当我说这需要动态 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)

SQL Fiddle

构建逗号分隔的列列表与之前使用 for xml path('') 的查询相同。在交叉应用中,为每一行构造了一个 XML,用于查询子查询中的值和元素名称。元素名称对应于列名称,并使用 local-name(.) 进行访问。使用 nodes() 表达式对一行的值进行逆透视(甚至是一个真实的单词)。 nodes() 还确保 idwarehouse 不会作为列返回。

关于SQL-当值为1时获取列名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16784999/

相关文章:

sql - INSERT 多行与 RETURNING 子句中的 ID 组合

SQL Server 项目在部署后执行多个脚本

sql - Oracle 将多行合并为一个具有不同标题的行

sql - 何时使用 NEWID 或 NEWSEQUENTIALID 以及为什么

sql-server - SQL Server 全文搜索 - 多对多关系

当我使用 LIKE 运算符时,SQL-Server 会忽略我的 COLLATION

java - .NET SQL 插入速度比 JDBC 慢? (JDBC 快 4 倍)

mysql - 销售点定义

sql-server - SSDT-BI 可以与 SQL Server 2008 R2 一起使用吗?

sql-server-2008 - 无法修改SSMS中的维护计划