Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Transforme o resultado vertical em modo horizontal (T-SQL)


Como já foi dito, isso não é realmente possível, o mais próximo que você pode chegar é:
January2014CalculationDate | January2014PLResult | February2014CalculationDate | February2014PLResult
---------------------------+---------------------+-----------------------------+------------------
    2014-01-02             |       100           |       2014-02-03            |       300
    2014-01-03             |       200           |       2014-02-04            |       400
    NULL                   |       NULL          |       2014-02-27            |       500

E mesmo isso não é simples e eu ainda aconselharia lidar com formatação assim fora do sql. O primeiro passo é particionar os dados por mês e, em seguida, classificar as datas em cada mês:
SELECT  CalculationDate,
        PLResult,
        CalculationMonth,
        DenseRank = DENSE_RANK() OVER(PARTITION BY CalculationMonth ORDER BY CalculationDate)
FROM    (   SELECT  CalculationDate,
                    PLResult,
                    CalculationMonth = DATEADD(MONTH, DATEDIFF(MONTH, 0, CalculationDate), 0)
            FROM    #PLResultPerDay
        ) pl;

Isto dá:
CalculationDate PLResult    CalculationMonth    DenseRank
2014-01-02      100         2014-01-01          1
2014-01-03      200         2014-01-01          2
2014-02-03      300         2014-02-01          1
2014-02-04      400         2014-02-01          2
2014-02-27      500         2014-02-01          3

Você pode então dinamizar esses dados:
WITH Data AS
(   SELECT  CalculationDate,
            PLResult,
            CalculationMonth,
            DenseRank = DENSE_RANK() OVER(PARTITION BY CalculationMonth ORDER BY CalculationDate)
    FROM    (   SELECT  CalculationDate,
                        PLResult,
                        CalculationMonth = DATEADD(MONTH, DATEDIFF(MONTH, 0, CalculationDate), 0)
                FROM    #PLResultPerDay
            ) pl
)
SELECT  Jan2014CalcDate = MIN(CASE WHEN CalculationMonth = '20140101' THEN CalculationDate END),
        Jan2014Result = SUM(CASE WHEN CalculationMonth = '20140101' THEN PLResult END),
        Feb2014CalcDate = MIN(CASE WHEN CalculationMonth = '20140201' THEN CalculationDate END),
        Feb2014Result = SUM(CASE WHEN CalculationMonth = '20140201' THEN PLResult END)
FROM    Data
GROUP BY DenseRank
ORDER BY DenseRank;

Isto dá:
Jan2014CalcDate Jan2014Result   Feb2014CalcDate Feb2014Result
2014-01-02      100             2014-02-03      300
2014-01-03      200             2014-02-04      400
NULL            NULL            2014-02-27      500

Então, como você tem um número dinâmico de meses, você precisa construir a instrução acima dinamicamente e usar SP_EXECUTESQL para executá-lo:
DECLARE @SQL NVARCHAR(MAX) = '';

WITH Months AS
(   SELECT  M,
            ColName = DATENAME(MONTH, M) + DATENAME(YEAR, M),
            CharFormat = CONVERT(VARCHAR(8), M, 112)
    FROM    (   SELECT  DISTINCT M = DATEADD(MONTH, DATEDIFF(MONTH, 0, CalculationDate), 0)
                FROM    #PLResultPerDay
            ) m
)
SELECT  @SQL = 'WITH Data AS
                (   SELECT  CalculationDate,
                            PLResult,
                            CalculationMonth,
                            DenseRank = DENSE_RANK() OVER(PARTITION BY CalculationMonth ORDER BY CalculationDate)
                    FROM    (   SELECT  CalculationDate,
                                        PLResult,
                                        CalculationMonth = DATEADD(MONTH, DATEDIFF(MONTH, 0, CalculationDate), 0)
                                FROM    #PLResultPerDay
                            ) pl
                )
                SELECT  ' + 
                STUFF(( SELECT  ', ' + ColName + 'CalculationDate = MIN(CASE WHEN CalculationMonth = ''' + CharFormat + ''' THEN CalculationDate END), ' + 
                                ColName + 'PLResult = SUM(CASE WHEN CalculationMonth = ''' + CharFormat + ''' THEN PLResult END)'
                        FROM    Months
                        ORDER BY M
                        FOR XML PATH(''), TYPE
                    ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + 
                'FROM   Data
                GROUP BY DenseRank
                ORDER BY DenseRank;';

EXECUTE SP_EXECUTESQL @SQL;

Exemplo no SQL Fiddle

Observe que ainda desaconselho essa técnica e acho que o SQL deve ser deixado para armazenar/recuperar dados e a camada de apresentação para formatá-los