Transform vertical result into horizontal mode (T-SQL)(将垂直结果转换为水平模式 (T-SQL))
问题描述
以下是示例数据:
计算日期PLResult
2014-01-02     100     
2014-01-03     200     
2014-02-03    300     
2014-02-04     400     
2014-02-27    500     
这是预期的结果(以逻辑格式):
Here are the expected result (in logical format) :
一月        二月      ;              
CalculationDatePLResultCalculationDatePLResult 
2014-01-02     100     2014-02-03    300      知识库>
2014-01-03     200     2014-02-04    400      知识库>
                ;            2014-02-27     500      
这是预期的结果(使用 T-SQL 查询):
Here are the expected result (using T-SQL Query) :
Jan-CalculationDateJan-PLResultFeb-CalculationDateFeb-PLResult 
2014-01-02        100           2014-02-03     ;   300            
2014-01-03        200           2014-02-04     ;    400            
                ;                     2014-02-27      ;   500           
目标:
- 按月份对结果进行分类.在上面的示例中,一月份的结果放在一月份的细分中.
 - 月数可以是动态的.在上面的例子中,它只显示了 1 月和 2 月,因为只有 2 个月的结果
 - 结果将通过 Excel 显示.其实我可以查询多个查询表来汇总不同月份的结果,但是如果可以通过一个查询返回所有结果,那么维护和调试会更容易.
 
以下是填充示例数据的脚本:
Here are the scripts to populate the sample data : 
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 )
到目前为止,这是我构建查询的尝试:
So far here is my attempt in building the query : 
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
推荐答案
正如人们所说,这实际上是不可能的,你能得到的最接近的是:
As has been said this isn't actually possible, the closest you could get is:
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 之外处理这样的格式.第一步是按月对数据进行分区,然后对每个月的日期进行排序:
And even that is not simple and I would still advise handling formatting like this outside of sql. The first step is to partition the data by month, and then rank the dates in each month:
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
然后您可以旋转这些数据:
You can then pivot this data:
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 来运行它:
Then since you have a dynamic number of months you need to build the above statement dynamically and use SP_EXECUTESQL to run it:
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 Fiddle 示例
请注意,我仍然建议不要使用这种技术,并认为 SQL 应该用于存储/检索数据,以及用于格式化数据的表示层
这篇关于将垂直结果转换为水平模式 (T-SQL)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:将垂直结果转换为水平模式 (T-SQL)
				
        
 
            
        - 以一个值为轴心,但将一行上的数据按另一行分组? 2022-01-01
 - 远程 mySQL 连接抛出“无法使用旧的不安全身份验证连接到 MySQL 4.1+"来自 XAMPP 的错误 2022-01-01
 - 导入具有可变标题的 Excel 文件 2021-01-01
 - 在SQL中,如何为每个组选择前2行 2021-01-01
 - 如何将 SonarQube 6.7 从 MySQL 迁移到 postgresql 2022-01-01
 - 更改自动增量起始编号? 2021-01-01
 - SQL 临时表问题 2022-01-01
 - 如何将 Byte[] 插入 SQL Server VARBINARY 列 2021-01-01
 - 如何使用 pip 安装 Python MySQLdb 模块? 2021-01-01
 - 使用 Oracle PL/SQL developer 生成测试数据 2021-01-01
 
						
						
						
						
						
				
				
				
				