我想知道是否有可能。我有3张桌子:
Item ItemProperty Property
ItemUID ItemUID PropertyUID
Name PropertyUID Name
... Value ....
但是我想要一个查询,它返回一行中的所有内容,并将属性的名称作为列名称,如此
ItemUID ItemName Property1 Property2 Property2
109-2... PostalCard Value1 Value2 Value3
有可能吗?我希望它以这种特定格式而不是数据格式的原因是我们受限于我们的工具之一。
我想指定查询只返回1行,而不是多个项目的数据表,因为有些项目只能包含1个属性而其他项目超过5-10,会有一个“WHERE ITEMUID = @ItemUID”类型的。
架构的SQLFiddle(我希望它有效吗?)http://sqlfiddle.com/#!3/70f34/2
答案 0 :(得分:1)
您需要的静态SQL将遵循:
SELECT pvt.ItemUID,
Property1 = pvt.[1],
Property2 = pvt.[2],
Property3 = pvt.[3]
FROM ( SELECT ItemUID,
PropertyUID,
RowNum = ROW_NUMBER() OVER(PARTITION BY ItemUID ORDER BY PropertyUID)
FROM ItemProperty
) AS ip
PIVOT
( MAX(PropertyUID)
FOR RowNum IN ([1], [2], [3])
) AS pvt;
这只是为每个propertyUID分配一个行号,然后根据此进行转动。枢轴函数需要MAX(PropertyUID)
,但MIN
可以很容易ItemUID
,因为RowNum
和DECLARE @pvt NVARCHAR(MAX),
@Cols NVARCHAR(MAX),
@SQL NVARCHAR(MAX),
@MaxProperties INT;
-- GET MAXIMUM NUMBER OF PROPERTIES FOR A SINGLE ITEM
SELECT TOP 1 @MaxProperties = COUNT(*)
FROM ItemProperty
GROUP BY ItemUID
ORDER BY COUNT(*) DESC;
-- CREATE A STRING LIKE '[1],[2],[3]...' TO USE INSIDE PIVOT
SET @pvt = STUFF((SELECT TOP (@MaxProperties) ',' + QUOTENAME(ROW_NUMBER() OVER(ORDER BY object_id))
FROM sys.all_objects
FOR XML PATH('')), 1, 1, '');
-- CREATE A STRING LIKE 'Property1 = pvt.[1],Property2 = pvt.[2]...' TO USE IN SELECT
SET @Cols = STUFF((SELECT TOP (@MaxProperties) ',Property' + CAST(ROW_NUMBER() OVER(ORDER BY object_id) AS VARCHAR(10))
+ ' = pvt.' + QUOTENAME(ROW_NUMBER() OVER(ORDER BY object_id))
FROM sys.all_objects
FOR XML PATH('')), 1, 1, '');
-- BUILD SQL TO USE
SET @SQL = 'SELECT pvt.ItemUID,' + @Cols + '
FROM ( SELECT ItemUID,
PropertyUID,
RowNum = ROW_NUMBER() OVER(PARTITION BY ItemUID ORDER BY PropertyUID)
FROM ItemProperty
) AS ip
PIVOT
( MAX(PropertyUID)
FOR RowNum IN (' + @pvt + ')
) AS pvt;';
-- EXECUTE THE SQL THAT HAS BEEN DYNAMICALLY BUILT
EXECUTE sp_executesql @SQL;
的每个组合都是唯一的,只有一个属性可供选择从
如果它是不同数量的属性,那么您将需要使用动态SQL来进行透视,最终结果将类似,但您需要使用最大数量的属性来创建SQL:
FOR XML PATH(''), TYPE
<强> Example on SQL Fiddle 强>
N.B。我通常会建议使用.value
和XQuery方法SET @Cols = STUFF((SELECT TOP (10) ',Property' + CAST(ROW_NUMBER() OVER(ORDER BY object_id) AS VARCHAR(10))
+ ' = pvt.' + QUOTENAME(ROW_NUMBER() OVER(ORDER BY object_id))
FROM sys.all_objects
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
来创建SQL,但由于它只是连接的整数,所以我知道没有特殊字符所以不必担心这些不是正确逃脱,例如
DECLARE @ItemUID INT = 1;
DECLARE @pvt NVARCHAR(MAX),
@Cols NVARCHAR(MAX),
@SQL NVARCHAR(MAX),
@MaxProperties INT;
-- GET MAXIMUM NUMBER OF PROPERTIES FOR A SINGLE ITEM
SELECT @MaxProperties = COUNT(*)
FROM ItemProperty
WHERE ItemUID = @ItemUID
GROUP BY ItemUID
ORDER BY COUNT(*) DESC;
-- CREATE A STRING LIKE '[1],[2],[3]...' TO USE INSIDE PIVOT
SET @pvt = STUFF((SELECT TOP (@MaxProperties) ',' + QUOTENAME(ROW_NUMBER() OVER(ORDER BY object_id))
FROM sys.all_objects
FOR XML PATH('')), 1, 1, '');
-- CREATE A STRING LIKE 'Property1 = pvt.[1],Property2 = pvt.[2]...' TO USE IN SELECT
SET @Cols = STUFF((SELECT TOP (@MaxProperties) ',Property' + CAST(ROW_NUMBER() OVER(ORDER BY object_id) AS VARCHAR(10))
+ ' = pvt.' + QUOTENAME(ROW_NUMBER() OVER(ORDER BY object_id))
FROM sys.all_objects
FOR XML PATH('')), 1, 1, '');
-- BUILD SQL TO USE
SET @SQL = 'SELECT pvt.ItemUID,' + @Cols + '
FROM ( SELECT ItemUID,
PropertyUID,
RowNum = ROW_NUMBER() OVER(PARTITION BY ItemUID ORDER BY PropertyUID)
FROM ItemProperty
WHERE ItemUID = @ItemUID
) AS ip
PIVOT
( MAX(PropertyUID)
FOR RowNum IN (' + @pvt + ')
) AS pvt;';
-- EXECUTE THE SQL THAT HAS BEEN DYNAMICALLY BUILT
EXECUTE sp_executesql @SQL, N'@ItemUID INT', @ItemUID;
修改强>
如果你想将它限制为单个项目,那么你只需要添加几个WHERE子句(以获得计数,以及执行动态sql时):
{{1}}
答案 1 :(得分:0)
您必须以这种方式使用Pivoting,您可以将行转换为列。见this示例