10

我有一个表'propertyvalues',如下所示:

ID FileID 属性值
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
......
等等

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

 
FileID 名称 大小 类型
x 1.pdf 12567 应用程序/pdf
y 2.pdf 23576 申请/pdf
4

4 回答 4

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)
于 2012-09-27T10:49:51.943 回答
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版本的效率如何。

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

于 2012-09-27T11:56:45.617 回答
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
于 2013-10-01T00:38:51.593 回答
-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'
于 2012-09-27T10:54:04.013 回答