T:SQL:从行中选择值作为列

Posted

技术标签:

【中文标题】T:SQL:从行中选择值作为列【英文标题】:T:SQL: select values from rows as columns 【发布时间】:2012-10-17 16:11:29 【问题描述】:

我有一个 Profiles 表格,以行样式存储配置文件属性值,例如:

[ProfileID]     [PropertyDefinitionID]      [PropertyValue]
1               6                           Jone
1               7                           Smith
1               8                           Mr
1               3                           50000

还有另一个属性定义表:

[PropertyDefinitionID]  [PropertyName]
6                       FirstName
7                       LastName
8                       Prefix
3                       Salary

如何使用PIVOT或任何其他方式以这种方式显示它:

[ProfileID] [FirstName] [LastName]  [Salary]
1           Jone        Smith       5000

【问题讨论】:

【参考方案1】:

不用PIVOT关键字很容易做到这一点,只需分组

select
    P.ProfileID,
    min(case when PD.PropertyName = 'FirstName' then P.PropertyValue else null end) as FirstName,
    min(case when PD.PropertyName = 'LastName' then P.PropertyValue else null end) as LastName,
    min(case when PD.PropertyName = 'Salary' then P.PropertyValue else null end) as Salary
from Profiles as P
    left outer join PropertyDefinitions as PD on PD.PropertyDefinitionID = P.PropertyDefinitionID
group by P.ProfileID

您也可以使用 PIVOT 关键字来做到这一点

select
    *
from
(
    select P.ProfileID, P.PropertyValue, PD.PropertyName
    from Profiles as P
        left outer join PropertyDefinitions as PD on PD.PropertyDefinitionID = P.PropertyDefinitionID
) as P
    pivot
    (
        min(P.PropertyValue)
        for P.PropertyName in ([FirstName], [LastName], [Salary])
    ) as PIV

更新:关于属性的动态数量 - 查看Increment value in SQL SELECT statement

【讨论】:

感谢您的贡献,这两种方法都解决了这个问题,但是如果我们考虑性能,哪一种更快?【参考方案2】:

您可能需要将未知数量的PropertyName's 转换为列。如果是这种情况,那么您可以使用动态 sql 来生成结果:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(PropertyName) 
                    from propertydefinitions
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT profileid, ' + @cols + ' from 
             (
                select p.profileid,
                  p.propertyvalue,
                  d.propertyname
                from profiles p
                left join propertydefinitions d
                  on p.PropertyDefinitionID = d.PropertyDefinitionID
            ) x
            pivot 
            (
                max(propertyvalue)
                for propertyname in (' + @cols + ')
            ) p '

execute(@query)

见SQL Fiddle with Demo。

【讨论】:

当您只需要将列连接到变量时,您不需要使用for xml。当您尝试从表中选择数据时,也可能存在安全问题,例如,用户可以对过程具有权限,但对表没有权限。看看我的答案 - ***.com/questions/13055295/… @RomanPekar 有多种不同的方式来连接列,这是我选择使用的方法。

以上是关于T:SQL:从行中选择值作为列的主要内容,如果未能解决你的问题,请参考以下文章

oracle如何从行中选择元组

Pandas 用 NaN 值填充列中的单元格,从行中的其他单元格中获取值

如何从行中获取/打印值[重复]

如果满足某些条件,则从行中获取信息

按列分组并选择具有多个最小值的行中的所有字段

如何从特定小时范围内的行中选择最小值?