我有一个表'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
答案 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'