从表中选择值作为列标题

时间:2012-09-27 10:46:29

标签: sql sql-server sql-server-2008 tsql pivot

我有一个表'propertyvalues'如下:

ID  FileID  Property  Value
1 x Name 1.pdf
2 x Size 12567
3 x Type application/pdf
4 y Name 2.pdf
5 y Size 23576
6 y Type application/pdf
......
and so on

如何在上表中编写SQL查询以获取如下所示的结果

 
FileID  Name     Size      Type
x 1.pdf 12567 application/pdf
y 2.pdf 23576 application/pdf

4 个答案:

答案 0 :(得分:11)

您没有指定RDBMS,如果您知道要转换的列数,那么您可以对值进行硬编码:

select FileId,
  max(case when property = 'Name' then value end) Name,
  max(case when property = 'Size' then value end) Size,
  max(case when property = 'Type' then value end) Type
from yourtable
group by FileId

这基本上是PIVOT函数,有些RDBMS会有PIVOT,如果你这样做,你可以使用以下内容,PIVOT在SQL Server,Oracle中可用:

select *
from 
(
  select FileId, Property, Value
  from yourTable
) x
pivot
(
  max(value)
  for property in ([Name], [Size], [Type])
) p

如果要转换的列数未知,则可以使用动态PIVOT。这将获取要在运行时转换的列的列表:

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

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

set @query = 'SELECT ' + @cols + ' from 
             (
                select FileId, Property, Value
                from yourtable
            ) x
            pivot 
            (
                max(value)
                for Property in (' + @cols + ')
            ) p '

execute(@query)

答案 1 :(得分:9)

具有连接的版本,无论缺少哪些行都可以使用:

SELECT  
    pd.FileID 
  , p1.Value  AS Name
  , p2.Value  AS Size
  , p3.Value  AS Type
FROM
        ( SELECT DISTINCT FileID
          FROM propertyvalues 
        ) AS pd
    LEFT JOIN
        propertyvalues AS p1
            ON  p1.FileID = pd.FileID 
            AND p1.Property = 'Name'
    LEFT JOIN
        propertyvalues AS p2
            ON  p2.FileID = pd.FileID 
            AND p2.Property = 'Size'
    LEFT JOIN
        propertyvalues AS p3
            ON  p3.FileID = pd.FileID
            AND p3.Property = 'Type' ;

如果您的表中FileID是主键,则可以将DISTINCT子查询替换为该表。


关于效率,它取决于很多因素。例子:

  • 所有FileID都包含名称,大小和类型的行,而没有其他属性(并且您的表在(FileID, Property)上有聚簇索引)?然后MAX(CASE...)版本的表现会非常好,因为无论如何都必须扫描整个表格。

  • 是否有(多个)超过3个属性且许多FileID没有名称,大小和类型,那么JOIN版本适用于(Property, FileID) INCLUDE (Value)上的索引此索引数据将用于连接。

  • 不确定PIVOT版本的效率如何。

我建议您在选择使用哪个版本之前,在您的环境(版本,磁盘,内存,设置等)中测试各种版本的数据和表格大小。

答案 2 :(得分:0)

Create function [dbo].[AF_TableColumns](@table_name nvarchar(55))
returns nvarchar(4000) as
begin
declare @str nvarchar(4000)
    select @str = cast(rtrim(ltrim(column_name)) as nvarchar(500)) + coalesce('         ' + @str , '            ') 
    from information_schema.columns
    where table_name = @table_name
    group by table_name, column_name, ordinal_position 
    order by ordinal_position DESC
return @str
end

--select dbo.AF_TableColumns('YourTable') Select * from YourTable

答案 3 :(得分:-1)

select 
  p1.FileID as FileID,
  p1.Value as Name,
  p2.Value as Size,
  p3.Value as Type
from 
  propertyvalues as p1 join 
  propertyvalues as p2 on p1.FileID = p2.FileID join 
  propertyvalues as p3 on p1.FileID = p3.FileID
where
  p1.Property='Name' AND p2.Property='Size' AND p3.Property='Type'