Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 将垂直结果转换为水平模式(T-SQL)_Sql Server_Sql Server 2008_Tsql_Sql Server 2012_Pivot - Fatal编程技术网

Sql server 将垂直结果转换为水平模式(T-SQL)

Sql server 将垂直结果转换为水平模式(T-SQL),sql-server,sql-server-2008,tsql,sql-server-2012,pivot,Sql Server,Sql Server 2008,Tsql,Sql Server 2012,Pivot,以下是示例数据: CalculationDatePLResult 2014-01-02100 2014-01-03200 2014-02-03300 2014-02-04400 2014-02-27500 以下是预期结果(逻辑格式): 一月至二月 CalculationDatePLResultCalculationDatePLResult 2014-01-021002014-02-03300 2014-01-032002014-02-04400 2014-02-27500 以下是预期结果(使用T

以下是示例数据:

CalculationDatePLResult
2014-01-02100
2014-01-03200
2014-02-03300
2014-02-04400
2014-02-27500

以下是预期结果(逻辑格式):

一月至二月
CalculationDatePLResultCalculationDatePLResult
2014-01-021002014-02-03300
2014-01-032002014-02-04400
2014-02-27500

以下是预期结果(使用T-SQL查询):

一月计算日期一月结果EB计算日期二月结果
2014-01-021002014-02-03300
2014-01-032002014-02-04400
2014-02-27500

目标:

  • 根据月份对结果进行分类。在上面的示例中,1月份的结果放在1月份的细分中
  • 月数可以是动态的。在上面的示例中,它只显示一月和二月,因为只有两个月的结果
  • 结果将通过Excel显示。实际上,我可以查询多个查询表来聚合不同月份的结果,但是如果可以通过一个查询返回所有结果,那么维护和调试就会更容易
以下是填充示例数据的脚本:

CREATE TABLE #PLResultPerDay ( CalculationDate DATETIME, PLResult DECIMAL(18,8) )
INSERT INTO #PLResultPerDay ( CalculationDate, PLResult ) VALUES ('2014-01-02' , 100 )
INSERT INTO #PLResultPerDay ( CalculationDate, PLResult ) VALUES ('2014-01-03' , 200 )
INSERT INTO #PLResultPerDay ( CalculationDate, PLResult ) VALUES ('2014-02-03' , 300 )
INSERT INTO #PLResultPerDay ( CalculationDate, PLResult ) VALUES ('2014-02-04' , 400 )
到目前为止,我尝试构建查询:

SELECT 
    CalculationDate, [January], CalculationDate, [February]
FROM 
(
    SELECT CalculationDate, PLResult, DATENAME(MONTH, CalculationDate) AS [MTH]
    FROM #PLResultPerDay
) x
PIVOT
( 
    MIN(PLResult)
    FOR [MTH] IN ([January], [February])
) p

正如已经说过的那样,这实际上是不可能的,你能得到的最接近的结果是:

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
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
然后,您可以透视此数据:

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;
这使得:

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
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将返回4列。e、 g.
JanCalc、JanPL、FebCalc、FebPL
@MartinSmith:谢谢,我对预期结果做了一些更正。编辑后的结果仍然不可能,PIVOT无法以这种方式工作。这种类型的操作不应在SQL中进行,而应在使用SQL结果的代码中进行。关于“结果将显示在Excel中”。您可能很快就能在Reporting Services中使用矩阵控件获得所需的格式。非常感谢您为详细解释所做的努力。