【问题标题】:Pivot table data in tabular format, first column should be column name and rest should be value表格格式的数据透视表数据,第一列应该是列名,其余应该是值
【发布时间】:2013-03-28 10:13:51
【问题描述】:

我只是想比较产品,这就是为什么我需要以列格式显示具有这些属性的产品。第一列将显示属性,其余列显示每列的属性值。

简单的select语句如下

SELECT  product_Id,product_Name,product_Price ,product_Description,product_weight  
from tblProduct
WHERE  product_Id in (1139,1140,1144)

现在我想以以下方式显示我的输出

我知道我需要使用 pivot 来获得所需的输出。我已经尝试过以下方式

SELECT MAX(ISNULL([1139],'')),MAX(ISNULL([1140],'')),MAX(ISNULL([1144],'')) 
FROM
(
  SELECT product_Id,product_Name,product_Price,product_Description,product_weight 
  FROM tblProduct where product_Id in (1139,1140,1144)
)s 
PIVOT
(
  MAX(product_Name)
  FOR product_Id in ([1139],[1140],[1144])
) AS PVT

但这仅适用于单个列,但我需要所有属性。

【问题讨论】:

    标签: sql sql-server sql-server-2008-r2 pivot unpivot


    【解决方案1】:

    由于您尝试聚合存在于多个列中的属性,这表明您需要同时应用 UNPIVOTPIVOT 函数。

    UNPIVOT 将获取您的列值并将它们转换为行。 unpivot 的代码类似于:

    select product_id, header, value
    from
    (
      select product_id, 
        product_name, 
        cast(product_price as varchar(10)) product_price, 
        product_weight
      from tblProduct
    ) p
    unpivot
    (
      value
      for header in (product_name, product_price, product_weight)
    ) unp
    

    SQL Fiddle with Demo。您会注意到其中有一个子查询将product_price 列转换为varchar。这是因为行中所需列的数据类型必须相同。因此,您可能必须执行数据转换才能使其正常工作。

    unpivot 生成的结果如下所示:

    | PRODUCT_ID |         HEADER | VALUE |
    ---------------------------------------
    |        141 |   product_name |  A141 |
    |        141 |  product_price |   200 |
    |        141 | product_weight | 200gm |
    

    数据在行中后,您可以将 PIVOT 函数应用于product_id 列值。

    select header, [141], [142], [143], [144]
    from
    (
      select product_id, header, value
      from
      (
        select product_id, 
          product_name, 
          cast(product_price as varchar(10)) product_price, 
          product_weight
        from tblProduct
      ) p
      unpivot
      (
        value
        for header in (product_name, product_price, product_weight)
      ) unp
    ) d
    pivot
    (
      max(value)
      for product_id in ([141], [142], [143], [144])
    ) piv
    

    SQL Fiddle with Demo。这给出了一个结果:

    |         HEADER |   141 |   142 |   143 |   144 |
    --------------------------------------------------
    |   product_name |  A141 |  A142 |  A143 |  A144 |
    |  product_price |   200 |   300 |  4000 |  5000 |
    | product_weight | 200gm | 300gm | 400gm | 100gm |
    

    如果您想要将已知数量的product_id 值作为列,上述版本将非常有用。但是如果你有一个未知的数字,那么你会想要实现动态 SQL:

    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = STUFF((SELECT distinct ',' + QUOTENAME(product_id) 
                        from tblProduct
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT header, ' + @cols + ' 
                  from 
                 (
                    select product_id, header, value
                    from
                    (
                      select product_id, 
                        product_name, 
                        cast(product_price as varchar(10)) product_price, 
                        product_weight
                      from tblProduct
                    ) p
                    unpivot
                    (
                      value
                      for header in (product_name, product_price, product_weight)
                    ) unp
                ) x
                pivot 
                (
                    max(value)
                    for product_id in (' + @cols + ')
                ) p '
    
    execute(@query)
    

    SQL Fiddle with Demo。这将生成与查询的静态/硬编码版本相同的结果。

    【讨论】:

    • @rahularyansharma 谢谢,我添加了代码的动态版本,以防您有未知数量的 product_id 转换为列。
    • 你让我成为关键问题的粉丝 :)
    • 实际上我已经在存储过程 @ProductIds nvarchar(500) 中将 productIds 作为逗号分隔传递了
    • 选择列表中的元素数量超过了最大允许的 4096 个元素。
    • 我不想对所有列运行此查询,而不是只对我在 @ProductIds 变量中传递的 productsIds ......最多只能是 4 个
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2015-06-01
    • 2019-06-15
    • 1970-01-01
    • 2021-12-28
    • 2022-12-10
    相关资源
    最近更新 更多