【问题标题】:Sql pivot - but dont sum the valuesSql pivot - 但不要对值求和
【发布时间】:2013-07-18 13:31:35
【问题描述】:

我有一个看起来像这样的表架构

CREATE TABLE [dbo].[Discounts](
      [Id] [int] NOT NULL,
      [ProductId] [varchar(50)] NOT NULL,
      [LowerBoundDays] [int] NOT NULL,
      [UpperBoundDays] [int] NOT NULL,
      [Discount] [decimal](18, 4) NOT NULL,

还有一些这样的数据

        lower       upper discount(%)
product1  0         10          0
product1  10        30          1
product1  30        60          2
product1  60        90          3
product1  90        120         4
product2  0         10          0
product2  10        30          1
product2  30        60          2
product2  60        90          3
product2  90        120         4

如何进行数据透视查询以获得如下所示的 2 行:

            0-10    10-30   30-60   60-90   90-120
product1    0       1       2       3       4
product2    0       1       2       3       4

【问题讨论】:

    标签: sql sql-server pivot


    【解决方案1】:

    由于您使用的是 SQL Server,因此您可以通过多种方式将数据行转换为列。

    您可以使用带有 CASE 表达式的聚合函数来获取结果:

    select productid,
      max(case when lower = 0 and upper = 10 then discount end) [0-10],
      max(case when lower = 10 and upper = 30 then discount end) [10-30],
      max(case when lower = 30 and upper = 60 then discount end) [30-60],
      max(case when lower = 60 and upper = 90 then discount end) [60-90],
      max(case when lower = 90 and upper = 120 then discount end) [90-120]
    from CorporateSpread
    group by productid;
    

    SQL Fiddle with Demo

    如果您使用的是 SQL Server 2005+,那么您可以使用 PIVOT 函数:

    select productid, [0-10], [10-30], [30-60], [60-90],[90-120]
    from 
    (
      select productid,
        discount,
        cast(lower as varchar(10)) + '-' + cast(upper as varchar(10)) rng
      from CorporateSpread
    ) d
    pivot
    (
      max(discount)
      for rng in ([0-10], [10-30], [30-60], [60-90],[90-120])
    ) piv;
    

    SQL Fiddle with Demo

    如果您有已知数量的值,上述两个版本非常有效,但如果您有未知数量的范围,那么您将需要使用动态 SQL:

    DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = STUFF((SELECT distinct ',' + QUOTENAME(cast(lower as varchar(10)) + '-' + cast(upper as varchar(10))) 
                        from CorporateSpread
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    set @query = 'SELECT productid, ' + @cols + ' 
                from 
                (
                    select productid,
                      discount,
                      cast(lower as varchar(10)) + ''-'' + cast(upper as varchar(10)) rng
                    from CorporateSpread
                ) x
                pivot 
                (
                    max(discount)
                    for rng in (' + @cols + ')
                ) p '
    
    execute sp_executesql @query;
    

    SQL Fiddle with Demo。所有版本都会给出结果:

    | PRODUCTID | 0-10 | 10-30 | 30-60 | 60-90 | 90-120 |
    -----------------------------------------------------
    |  product1 |    0 |     1 |     2 |     3 |      4 |
    |  product2 |    0 |     1 |     2 |     3 |      4 |
    

    【讨论】:

    • 这是否意味着您的查询必须了解数据。正如您必须将日期范围硬编码到 case 表达式中一样。如果不同的产品有不同的日期范围怎么办。有没有办法变得更有活力?
    • @ChrisCa 查看我的编辑,我使用 PIVOT 函数添加了两个版本,一个版本使用动态 SQL
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    • 1970-01-01
    • 2020-06-28
    相关资源
    最近更新 更多