【问题标题】:SQL Select column-spanned data over row-spannedSQL 选择跨行数据而不是跨行数据
【发布时间】:2015-01-23 08:08:54
【问题描述】:

我有下表:

REPORT_MONTH    FORECAST_1  FORECAST_2  FORECAST_3  FORECAST_4  FORECAST_5  FORECAST_6  FORECAST_7  FORECAST_8  FORECAST_9  FORECAST_10 FORECAST_11 FORECAST_12
201501            23            23        14         51            25          27          28            29         36          35           12          42
201502            24            25        26         12            4           25          26            7           8          21           4           24

以上记录基于起始月份的未来十二个月的销售预测(例如:如果报告月份为 201501,Forecast_2 是指 2015 年 3 月的销售预测)

鉴于此架构,我想选择以下数据:

REPORT_MONTH    FORECAST_MONTH  FORECAST_VALUE
201501             201502             23
201501             201503             23
201501             201504             14
201501             201505             51
201501             201506             25
201501             201507             27
201501             201508             28
201501             201509             29
201501             201510             36
201501             201511             35
201501             201512             12
201501             201601             42
201502             201503             24
201502             201504             25
201502             201505             26
201502             201506             12
201502             201507             4
201502             201508             25
201502             201509             26
201502             201510             7
201502             201511             8
201502             201512             21
201502             201601             4
201502             201602             24

除非必须将 varchar 日期转换为日期时间,否则这是否可能?

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    不是最好的解决方案,但您可以使用一组unions:

    select report_month
    ,      substring(convert(varchar, dateadd(month, 1 /*month nr*/, convert(date, report_month + '01', 112)), 112), 1, 6) forcast_month
    ,      forecast_01 forecast_value
    from   tableName
    union
    all
    select report_month
    ,      substring(convert(varchar, dateadd(month, 2 /*month nr*/, convert(date, report_month + '01', 112)), 112), 1, 6) forcast_month
    ,      forecast_02 forecast_value
    from   tableName
    

    等等等等

    【讨论】:

    • UNION ALL 是要走的路,但你错过了一些事情。将列号添加到 REPORT_MONTH 以获得 FORECAST_MONTH,并且 FROM 表也丢失了。
    • @jarlh:谢谢。你是对的。这只是一些示例代码。我认为OP可能会自己解决其余的问题。这是关于概念,而不是“编写我的代码”。
    • 不,我不确定这是否可行。例如,如果报表月份为 201505,则 forecast_1 指的是 201506 的值。通过上述查询,无法区分 forecast_1 指的是哪个月份。
    【解决方案2】:

    您可以使用UNPIVOT 进行更简洁的查询:

    SELECT REPORT_MONTH, FORECAST_VALUE, 
           ROW_NUMBER() OVER (PARTITION BY REPORT_MONTH ORDER BY FORECAST) AS rn
    FROM 
       (SELECT REPORT_MONTH, FORECAST_1, FORECAST_2, FORECAST_3, ...etc
        FROM #FORECASTS) p
    UNPIVOT
       (FORECAST_VALUE FOR FORECAST IN (FORECAST_1, FORECAST_2, FORECAST_3, ...etc))AS unpvt;
    

    上述查询产生的输出是这样的:

    REPORT_MONTH    FORECAST_VALUE  rn
    ----------------------------------
    201501          23              1
    201501          23              2
    201501          14              3
    ....
    201502          24              1
    201502          25              2 
    201502          26              3
    .....
    

    您现在可以将上述查询包装在另一个查询中,并使用rnREPORT_MONTH 来计算FORECAST_MONTH

    SELECT REPORT_MONTH, 
           DATEADD(MONTH, rn, CONVERT(DATE, CONCAT(REPORT_MONTH, '01'))) AS FORECAST_MONTH, 
           FORECAST_VALUE
    FROM (
       SELECT REPORT_MONTH, FORECAST_VALUE, 
              ROW_NUMBER() OVER (PARTITION BY REPORT_MONTH ORDER BY FORECAST) AS rn
       FROM 
          (SELECT REPORT_MONTH, FORECAST_1, FORECAST_2, FORECAST_3, ...etc
           FROM #FORECASTS) p
       UNPIVOT
          (FORECAST_VALUE FOR FORECAST IN (FORECAST_1, FORECAST_2, FORECAST_3, ...etc ))AS unpvt
    ) t
    

    输出:

    REPORT_MONTH    FORECAST_MONTH  FORECAST_VALUE
    ----------------------------------------------
    201501          2015-02-01      23
    201501          2015-03-01      23
    201501          2015-04-01      14
    ... etc
    201502          2015-03-01      24
    201502          2015-04-01      25
    201502          2015-05-01      26
    ... etc
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-29
      • 1970-01-01
      • 2013-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多