我有一个表'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
我有一个表'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
您没有指定 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)
一个带有连接的版本,不管丢失的行如何:
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
版本的效率如何。
我的建议是在您选择使用哪个版本之前,在您的环境(版本、磁盘、内存、设置...)中使用您的数据和表大小测试各种版本。
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
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'