包含组和动态列名称的PIVOT

时间:2018-02-22 10:19:46

标签: sql sql-server tsql sql-server-2012

我有3个包含商品属性的表,因为每组商品都有不同数量的属性我将它们作为键值保存。

Package

| ID | Name    |
| 1  | TVs     |
| 2  | Laptops |

PackageItem

| ID | PackageId | Description  |
| 1  | 1         | Samsung TV   |
| 2  | 1         | Sony TV      |
| 3  | 2         | Apple laptop |
| 4  | 2         | Lenovo       |

PackageItemDetail

| ID | PackageItemId | Key               | Value    | PropertyOrder |
| 1  | 1             | Brand             | Samsung  | 1             |
| 2  | 1             | Size              | 42 inch  | 2             |
| 3  | 1             | Power consumption | A+       | 3             |
| 4  | 1             | Remote            | Smart    | 5             |
| 5  | 1             | Weight            | 15kg     | 4             |
| 6  | 2             | Brand             | Sony     | 1             |
| 7  | 2             | Size              | 50 inch  | 2             |
| 8  | 2             | Power consumption | A+++     | 3             |
| 9  | 2             | Remote            | Standard | 5             |
| 10 | 2             | Weight            | 20kg     | 4             |
| 11 | 3             | Brand             | Apple    | 1             |
| 12 | 3             | Procesor          | Intel    | 2             |
| 13 | 4             | Brand             | Lenovo   | 1             |
| 14 | 4             | Procesor          | Intel I7 | 2             |

如果我使用这些查询为特定包选择项目及其属性:

SELECT PID.[Key], PID.[Value] FROM PackageItemDetail PID (NOLOCK) JOIN PackageItem PI (NOLOCK) ON PID.PackageItemId=PI.Id
WHERE PI.PackageId=1 ORDER BY PID.PackageItemId, PID.PropertyOrder;

SELECT PID.[Key], PID.[Value] FROM PackageItemDetail PID (NOLOCK) JOIN PackageItem PI (NOLOCK) ON PID.PackageItemId=PI.Id
WHERE PI.PackageId=2 ORDER BY PID.PackageItemId, PID.PropertyOrder;

我得到了那些结果: enter image description here

enter image description here

每个套餐总是有相同的数字或属性,因此电视有5个属性,笔记本电脑有2个属性。

我希望将这些表转换为:

| Brand   | Size    | Power consumption | Weight | Remote   |
| Samsung | 42 inch | A+                | 15kg   | Smart    |
| Sony    | 50 inch | A+++              | 20kg   | Standard |

| Brand  | Procesor |
| Apple  | Intel    |
| Lenovo | Intel I7 |

我能够使用:

创建简单的Pivot
SELECT
    [Brand]
   ,[Procesor]
FROM
    ( SELECT
        PI.[Id]
       ,PID.[Key]
       ,PID.[Value]
      FROM
        PackageItemDetail PID ( NOLOCK )
        JOIN PackageItem PI ( NOLOCK ) ON PID.PackageItemId = PI.Id
      WHERE
        PI.PackageId = 2
    ) AS SourceTable PIVOT
( MAX(Value) FOR [Key] IN ( [Brand], [Procesor] ) ) AS PivotTable;

但这样我必须手动指定属性,但我想让它们动态化(因此相同的查询将适用于不同的包)

我已经使用示例数据创建了SQL Fiddle:http://sqlfiddle.com/#!18/e8c51/1

2 个答案:

答案 0 :(得分:1)

我尝试为您的问题应用动态SQL。

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)
SELECT @ColumnName= ISNULL(@ColumnName + ',','') 
       + QUOTENAME([Key])
FROM (SELECT DISTINCT [Key] FROM PackageItemDetail PID 
      JOIN PackageItem PI ON PID.PackageItemId = PI.Id
      WHERE PI.PackageId = 2) AS Courses
SET @DynamicPivotQuery = 
  N'SELECT
    '+ @ColumnName +'
  FROM
    ( SELECT
        PI.[Id]
       ,PID.[Key] 
       ,PID.[Value]
      FROM
        PackageItemDetail PID ( NOLOCK )
        JOIN PackageItem PI ( NOLOCK ) ON PID.PackageItemId = PI.Id
      WHERE
        PI.PackageId = 2
    ) AS SourceTable PIVOT
( MAX(Value) FOR [Key] IN (' + @ColumnName + ')) AS PivotTable'

EXEC sp_executesql @DynamicPivotQuery

以下是查询演示的链接:

  

http://sqlfiddle.com/#!18/e8c51/44

有关说明,您可以访问以下链接:

  

http://sqlhints.com/tag/dynamic-pivot-column-names/

答案 1 :(得分:0)

DECLARE @COLUMN1 VARCHAR(250),@STATEMENT1 NVARCHAR(MAX),@COLUMN2 VARCHAR(250),@STATEMENT2 NVARCHAR(MAX);

SELECT @COLUMN1 = COALESCE(@COLUMN1+',','')+QUOTENAME([Key]) FROM(
SELECT DISTINCT PID.[Key] FROM PackageItemDetail PID  JOIN PackageItem PI  ON PID.PackageItemId=PI.Id
WHERE PI.PackageId=1) A

SET @STATEMENT1 = N'
select  *from (
SELECT PID.[Key], PID.[Value] FROM PackageItemDetail PID  JOIN PackageItem PI  ON PID.PackageItemId=PI.Id
WHERE PI.PackageId=1 ) as a
PIVOT (MIN([Value]) FOR [Key] IN ('+@COLUMN1+'))AS P1
UNION ALL
select  *from (
SELECT PID.[Key], PID.[Value] FROM PackageItemDetail PID  JOIN PackageItem PI  ON PID.PackageItemId=PI.Id
WHERE PI.PackageId=1 ) as a
PIVOT (MAX([Value]) FOR [Key] IN ('+@COLUMN1+'))AS P2'

--PRINT @STATEMENT1
EXEC (@STATEMENT1)

SELECT @COLUMN2 = COALESCE(@COLUMN2+',','')+QUOTENAME([Key]) FROM(
SELECT DISTINCT PID.[Key] FROM PackageItemDetail PID  JOIN PackageItem PI  ON PID.PackageItemId=PI.Id
WHERE PI.PackageId=2) A1

SET @STATEMENT2 = N'
select  *from (
SELECT PID.[Key], PID.[Value] FROM PackageItemDetail PID  JOIN PackageItem PI  ON PID.PackageItemId=PI.Id
WHERE PI.PackageId=2) as a
PIVOT (MIN([Value]) FOR [Key] IN ('+@COLUMN2+'))AS P1
UNION ALL
select  *from (
SELECT PID.[Key], PID.[Value] FROM PackageItemDetail PID  JOIN PackageItem PI  ON PID.PackageItemId=PI.Id
WHERE PI.PackageId=2 ) as a
PIVOT (MAX([Value]) FOR [Key] IN ('+@COLUMN2+'))AS P2'

--PRINT @STATEMENT2
EXEC (@STATEMENT2)

输出@ STATEMENT1

Brand   Power consumption   Remote  Size    Weight
Samsung A+                  Smart   42 inch 15kg
Sony    A+++              Standard  50 inch 20kg

输出@ STATEMENT2

Brand   Procesor
Apple   Intel
Lenovo  Intel I7