将列名和数据获取到 SQL 中的行

Get column names and data to rows in SQL

我有一个 table,基本员工详细信息如下:

Table:tblEmployees

EmpID   Name    Contact   Sex
100     John    55555     M
200     Kate    44444     F
300     Sam     88888     M

我想获得如下特定员工的查询结果,其中 EmpID = 200

Col1    Col2
EmpID   200
Name    Kate
Sex     F

您可以使用交叉应用:

select t.*
from employees e
cross apply (values 
    ('empid', cast(empid as varchar(100))),
    ('name', name), 
    ('sex', sex)
) t(attr, value)
where e.empid = 200

据推测,empid 是一个数字,因此需要显式转换(否则 sql 服务器将尝试将姓名和性别转换为数字,这将失败)。

Demo on DB Fiddle:

attr  | value
:---- | :----
empid | 200  
name  | Kate 
sex   | F    

另一种选择是 XML

完全披露: 性能不如专线小巴的 CROSS APPLY (+1) 或 UNPIVOT。但它会动态地反透视几乎任何行、table、视图或临时查询,而无需实际使用动态 SQL.

例子

Declare @YourTable Table ([EmpID] varchar(50),[Name] varchar(50),[Contact] varchar(50),[Sex] varchar(50))  Insert Into @YourTable Values 
 (100,'John',55555,'M')
,(200,'Kate',44444,'F')
,(300,'Sam',88888,'M')

 Select A.EmpID
       ,C.*
 From @YourTable A
 Cross Apply ( values (convert(xml,(select a.* for XML Raw ))) ) B(XMLData)
 Cross Apply (
                Select Item  = xAttr.value('local-name(.)', 'varchar(100)')
                      ,Value = xAttr.value('.','varchar(max)')
                 From  XMLData.nodes('//@*') xNode(xAttr)
                 Where xAttr.value('local-name(.)', 'varchar(100)') not in ('EmpID','Other','Columns2Exclude')
             ) C

Returns

EmpID   Item    Value
100     Name    John
100     Contact 55555
100     Sex     M
200     Name    Kate
200     Contact 44444
200     Sex     F
300     Name    Sam
300     Contact 88888
300     Sex     M

编辑 - 如果对此处感兴趣,请使用 TVF 方法

Select A.EmpID
      ,B.*
 From  @YourTable A
 Cross Apply [dbo].[tvf-XML-UnPivot-Row]((Select A.* for XML RAW)) B

TVF

CREATE FUNCTION [dbo].[tvf-XML-UnPivot-Row](@XML xml)
Returns Table 
As
Return ( 
        Select Item  = xAttr.value('local-name(.)', 'varchar(100)')
              ,Value = xAttr.value('.','varchar(max)')
         From  @XML.nodes('//@*') xNode(xAttr)
)

或者涉及 3 个 UNION 的不太复杂的解决方案,假设字段名称是预先确定的。这可能在大表上表现更好。 如果您遇到性能问题,请分析执行计划并确保索引得到最佳利用。

由于您一次只寻找一名特定员工:

SELECT 'empid', convert(varchar(12), EmpID)
FROM tblEmployees
WHERE EmpID = 200
UNION ALL
SELECT 'name', name
FROM tblEmployees
WHERE EmpID = 200
UNION ALL
SELECT 'sex', sex
FROM tblEmployees
WHERE EmpID = 200

第一行 convert(varchar(12) 假设 EmpID 是一个 int 字段。