【问题标题】:SQL Server Pivot on multiple fieldsSQL Server 透视多个字段
【发布时间】:2016-03-08 08:41:59
【问题描述】:

我已经在这个网站上搜索了所有可能的解决方案,但仍然找不到我的 Pivot 问题的答案。

我有一个包含以下数据的表格。

Portfolio  |  Date      |  TotalLoans  | ActiveLoans  | TotalBalance
--------------------------------------------------------------------
P1         | 2015-12-31 |       1,000  |         900  |   100,000.00
P1         | 2015-11-30 |       1,100  |         800  |   100,100.00
P1         | 2015-10-31 |       1,200  |         700  |   100,200.00

我正在尝试使用以下输出创建一个支点(仅在 Portfolio = P1 的情况下)

Field        | 2015-12-31 | 2015-11-30 | 2015-10-31 |
-----------------------------------------------------
TotalLoans   |      1,000 |      1,100 |      1,200 |
ActiveLoans  |        900 |        800 |        700 |
TotalBalance |    100,000 |    100,100 |    100,200 | 

理想情况下,我正在寻找动态枢轴,但静态查询也可以,我可以尝试动态查询。

【问题讨论】:

    标签: sql sql-server pivot


    【解决方案1】:

    您需要先UNPIVOT 您的餐桌。您可以使用以下查询来完成:

    SELECT Portfolio, [Date], Val, ColType
    FROM (SELECT Portfolio, 
                 [Date], 
                 TotalLoans, 
                 ActiveLoans, 
                 TotalBalance 
          FROM mytable
          WHERE Portfolio = 'P1') AS srcUnpivot
          UNPIVOT (
             Val FOR ColType IN (TotalLoans, ActiveLoans, TotalBalance)) AS unpvt
    

    输出:

    Portfolio   Date      Val      ColType
    ===============================================
    P1         2015-12-31 1000     TotalLoans
    P1         2015-12-31 900      ActiveLoans
    P1         2015-12-31 100000   TotalBalance
    P1         2015-11-30 1100     TotalLoans
    P1         2015-11-30 800      ActiveLoans
    P1         2015-11-30 100100   TotalBalance
    P1         2015-10-31 1200     TotalLoans
    P1         2015-10-31 700      ActiveLoans
    P1         2015-10-31 100200   TotalBalance
    

    注意: 所有未透视字段必须是相同类型。上面的查询假定所有字段的类型都是 int。如果不是这种情况,那么您必须使用CAST

    使用上面的查询你可以申请PIVOT:

    SELECT Portfolio, ColType, [2015-12-31], [2015-11-30], [2015-10-31]
    FROM (
       ... above query here ...
    PIVOT (
       MAX(Val) FOR [Date] IN ([2015-12-31], [2015-11-30], [2015-10-31])) AS pvt
    

    【讨论】:

    • 很好的解决方案!从我这边 +1!
    • 我刚刚将您的解决方案的答案发布为动态 SQL,以避免手动写入日期值。
    【解决方案2】:

    这是作为动态 SQL 的 Giorgos Betsos 解决方案。这将无需显式写入日期值。

    请:如果您喜欢这样:不要将此解决方案标记为已接受,请将接受设置为 Giorgos Betsos。辛苦了!但你可以投票:-)

    CREATE TABLE #tbl(Portfolio VARCHAR(10),[Date] DATE,TotalLoans DECIMAL(10,4),ActiveLoans DECIMAL(10,4),TotalBalance DECIMAL(10,4));
    INSERT INTO #tbl VALUES
     ('P1','20151231',1000,900,100000.00)
    ,('P1','20151130',1100,800,100100.00)
    ,('P1','20151031',1200,700,100200.00);
    
    DECLARE @pvtColumns VARCHAR(MAX)=
    (
        STUFF(
        (
            SELECT DISTINCT ',['+CONVERT(VARCHAR(10), [Date] ,126) + ']'
            FROM #tbl
            FOR XML PATH('')
        )
        ,1,1,'')
    );
    
    DECLARE @cmd VARCHAR(MAX)=
    'SELECT Portfolio, ColType, ' + @pvtColumns + 
    ' FROM (
       SELECT Portfolio, [Date], Val, ColType
       FROM (SELECT Portfolio, 
                    [Date], 
                    TotalLoans, 
                    CAST(ActiveLoans AS DECIMAL(10,4)) AS ActiveLoans, 
                    TotalBalance 
             FROM #tbl AS mytable
             WHERE Portfolio = ''P1'') AS srcUnpivot
             UNPIVOT (
                Val FOR ColType IN (TotalLoans, ActiveLoans, TotalBalance)) AS unpvt
    ) AS srcPivot
    PIVOT (
       MAX(Val) FOR [Date] IN (' +  @pvtColumns + ')) AS pvt';
    
    EXEC (@cmd);
    

    【讨论】:

    • 感谢您的有用修改。
    【解决方案3】:

    您需要使用动态 SQL 并构建它们。请参阅http://social.technet.microsoft.com/wiki/contents/articles/17510.t-sql-dynamic-pivot-on-multiple-columns.aspx 上的示例

    这里是代码

    CREATE procedure CrossTab 
    (
    @select varchar(2000),
    @PivotCol varchar(100), 
    @Summaries varchar(100), 
    @GroupBy varchar(100),
    @OtherCols varchar(100) = Null
    )
    
    AS
    set nocount on
    set ansi_warnings off 
    declare @sql varchar(8000)
    
    Select @sql = ''
    
    Select @OtherCols= isNull(', ' + @OtherCols,'')
    
    create table #pivot_columns (pivot_column_name varchar(100))
    
    Select @sql='select ''' + replace( + @PivotCol,',',''' as pivot_column_name union all select ''')+''''
    
    insert into #pivot_columns
    exec(@sql)
    
    select @sql=''
    
    create table #pivot_columns_data (pivot_column_name varchar(100),pivot_column_data varchar(100))
    
    Select @PivotCol=''
    
    Select @PivotCol=min(pivot_column_name) from #pivot_columns
    
    While @PivotCol>''
    Begin
        insert into #pivot_columns_data(pivot_column_name,pivot_column_data) 
        exec 
        (
        'select distinct ''' + @PivotCol +''' as pivot_column_name, convert(varchar(100),' + @PivotCol + ') as pivot_column_data    from 
        ('+
            @select
        +'
        ) T'
        )
    
        Select @PivotCol=min(pivot_column_name) from #pivot_columns where pivot_column_name>@PivotCol
    end 
    select 
        @sql = @sql + ', ' + 
        replace(
            replace(
                    @Summaries,'(','(CASE WHEN ' + Pivot_Column_name + '=''' + 
                    pivot_column_data + ''' THEN ' 
                        ),
                ')[', ' END) as [' + pivot_column_data 
                    )
    from #pivot_columns_data
    order by pivot_column_name
    
    exec 
    (
         'select ' + @GroupBy +@OtherCols +@sql + 
        ' from (
        '+
            @select 
        +'
        ) T
        GROUP BY ' + @GroupBy
    ) 
    drop table #pivot_columns
    drop table #pivot_columns_data
    
    set nocount off
    set ansi_warnings on
    

    用法

    EXEC CrossTab
    'SELECT LastName, OrderDate,shipcountry FROM northwind..Employees Employees 
    INNER JOIN northwind..Orders Orders ON (Employees.EmployeeID=Orders.EmployeeID) ',
    'shipcountry,Year(OrderDate)',
    'Count(LastName)[]',
    'LastName'
    

    【讨论】:

      【解决方案4】:

      分几步进行:

      if object_id('tempdb..#Data') is null
          CREATE TABLE #Data
              ([Portfolio] varchar(2), [Date] datetime, 
               [TotalLoans] decimal(9,2), [ActiveLoans] int, [TotalBalance] decimal(9,2))
          ;
      
      INSERT INTO #Data
          ([Portfolio], [Date], [TotalLoans], [ActiveLoans], [TotalBalance])
      VALUES
          ('P1', '2015-12-31', 1000, 900, 100000.00),
          ('P1', '2015-11-30', 1100, 800, 100100.00),
          ('P2', '2015-10-31', 1200, 700, 100200.00)
      ;
      
      WITH Transposed AS (
          --First reorganise the data, creating unions like this, by column
          --Assumption is that you are not interested in [Portfolio]
          SELECT [Portfolio], [Date], [TotalLoans] AS Amount, 'TotalLoans' Field FROM #Data
          UNION SELECT [Portfolio], [Date], [ActiveLoans], 'ActiveLoans' FROM #Data
          UNION SELECT [Portfolio], [Date], [TotalBalance], 'TotalBalance' FROM #Data
      )
      SELECT Field, [2015-10-31], [2015-11-30], [2015-12-31] --You can build a string with all the dates from your original data source
      FROM (
          SELECT [Date], [Field], [Amount] FROM Transposed
      ) d
      PIVOT (
          MAX(Amount)
          FOR [Date] IN ([2015-10-31], [2015-11-30], [2015-12-31])
      ) p
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-10
        • 1970-01-01
        • 1970-01-01
        • 2015-07-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多