sql >> データベース >  >> RDS >> Sqlserver

垂直方向の結果を水平方向のモードに変換する(T-SQL)

    これは実際には不可能であると言われているように、最も近いものは次のとおりです。

    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
    

    そしてそれでも簡単ではなく、SQLの外でこのようなフォーマットを処理することをお勧めします。最初のステップは、データを月ごとに分割してから、各月の日付をランク付けすることです。

    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;
    

    これにより:

    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
    

    次に、このデータをピボットできます:

    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;
    

    これにより:

    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
    

    次に、動的な月数があるため、上記のステートメントを動的に作成し、SP_EXECUTESQLを使用する必要があります。 実行するには:

    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;
    

    SQLフィドルの例

    注意してください。私はまだこの手法に反対することをお勧めします。SQLはデータの保存/取得と、データをフォーマットするためのプレゼンテーション層に任せるべきだと思います。




    1. コードファーストマイグレーションとストアドプロシージャ

    2. PostgreSQLで中央値を計算する方法

    3. SQLServerのテーブルのすべての列から一意の値を取得する方法

    4. MySQLストアドプロシージャまたはPHPコード?