如何使用t-sql将动态7天行转换为列

时间:2014-01-29 16:06:25

标签: sql tsql

背景资料 我有一个大表400M +行每天都在变化(一天数据丢失了新的一天数据下降)该表在“day”字段上分区,因此有31个分区。 表中的每一行都有类似的数据:

ID, Postcode, DeliveryPoint, Quantity, Day, Month
1   SN1 1BG   A1               6        29    1
2   SN1 1BG   A1               1        28    1
3   SN1 1BG   A2               2        27    1
4   SN1 1BG   A1               3        28    1
5   SN2 1AQ   B1               1        29    12
6   SN1 1BG   A1               2        26    12

我需要以以下格式提取7天的数据:

Postcode, Deliverypoint, 7dayAverage, Day1,day2,Day3,Day4,Day5,Day6,Day7  
SN1 1BG      A1             2          0    1    2    1    3    4   0

我可以轻松提取7天的数据,但需要创建如上所示的柱状版本。

我有这样的事情:

select postcode,deliverypoint,
sum (case  day when 23 then quantity else 0 end) as day1,
sum (case  day when 24 then quantity  else 0 end) as day2,
sum(case  day when 25 then quantity  else 0 end) as day3,
sum(case  day when 26 then quantity  else 0 end) as day4,
sum(case  day when 27 then quantity  else 0 end) as day5,
sum(case  day when 28 then quantity  else 0 end) as day6,
sum(case  day when 29 then quantity  else 0 end) as day7,
sum(quantity)*1.0/@daysinweek as wkavg
into #allweekdp
from maintable dp with (nolock)
where day in (select day from #days)
group by postcode,deliverypoint

其中#days包含7天内的日期编号。

但正如你所看到的,我已经将日期数字硬编码到查询中,我想将它们从我的临时表#days中删除,但是看不到这样做的方法(数组会很完美)这里)

或者我是以完全错误的方式解决这个问题?

亲切的问候

史蒂夫

2 个答案:

答案 0 :(得分:0)

如果我理解正确,我会做的是:

  1. 将日期和月份列转换为日期时间值,
  2. 获取每个日期的一周的第一天和工作日的一天(1-7),
  3. 在一周的第一天转动数据和分组
  4. 见这里:sqlfiddle

答案 1 :(得分:0)

正如utexaspunk建议的那样,Pivot可能是最佳选择。我从来没有对枢轴感到满意,并且倾向于手动转动它,所以我控制一切看起来如何,所以我使用类似的解决方案来解决问题。不知道我的方式和utexaspunk之间的表现如何比较。

Declare @Min_Day Integer = Select MIN(day) as Min_Day From #days;

With Day_Coding_CTE as (
Select Distinct day
    , day - @Min_Day + 1 as Day_Label

From #days
)

, Non_Columnar_CTE as (
Select dp.postcode
    , dp.deliverypoint
    , d.day
    , c.Day_Label
    , SUM(quantity) as Quantity

From maintable dp with (nolock)
    Left Outer Join #days d
        on dp.day = d.day --It also seems like you'll need more criteria here, but you'll have to figure out what those should be
    Left Outer Join Day_Coding_CTE c
        on d.day = c.day
)

Select postcode
    , deliverypoint
    , SUM(Case
        When Day_Label = 1
            Then Quantity
            Else 0
        End) as Day1
    , SUM(Case
        When Day_Label = 2
            Then Quantity
            Else 0
        End) as Day2
    , SUM(Case
        When Day_Label = 3
            Then Quantity
            Else 0
        End) as Day3
    , SUM(Case
        When Day_Label = 4
            Then Quantity
            Else 0
        End) as Day4
    , SUM(Case
        When Day_Label = 5
            Then Quantity
            Else 0
        End) as Day5
    , SUM(Case
        When Day_Label = 6
            Then Quantity
            Else 0
        End) as Day6
    , SUM(Case
        When Day_Label = 7
            Then Quantity
            Else 0
        End) as Day7
    , SUM(Quantity)/@daysinweek as wkavg

From Non_Columnar_CTE

Group by postcode
    deliverypoint