4

I have searched this website for all possible solutions but still can't find an answer for my Pivot problem.

I have a table with the following data.

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

I am trying to create a pivot with the following output (only where 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 | 

Ideally, I am looking for a dynamic pivot, but a static query would do as well and I can try a dynamic query out of that.

4 Answers4

4

You need first to UNPIVOT your table. You can do it using this query:

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

Output:

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

Note: All unpivoted fields must be of the same type. The query above assumes a type of int for all fields. If this is not the case then you have to use CAST.

Using the above query you can apply 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
Giorgos Betsos
  • 71,379
  • 9
  • 63
  • 98
4

This is Giorgos Betsos solution as dynamic SQL. This will deal without the need to write the date values explicitly.

Please: If you like this: Do not mark this solution as accepted, set the acceptance to Giorgos Betsos. There's the hard work! But you may vote on it :-)

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);
Shnugo
  • 66,100
  • 9
  • 53
  • 114
1

You need to use Dyanmic SQL and construct them. See examples at http://social.technet.microsoft.com/wiki/contents/articles/17510.t-sql-dynamic-pivot-on-multiple-columns.aspx

Here is the code

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

Usage

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'
Madhivanan
  • 13,470
  • 1
  • 24
  • 29
1

Do it in several steps:

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
Tamayi
  • 143
  • 4