以列名作为日期的逆透视

Unpivot with column name as date

我有以下交叉表格式的数据:

prod_codigo  esps_fecini  day1    day2    day3    day4    day5  day6  day7
1077         2018-11-12   200.00  200.00  250.00  250.00  0.00  0.00  0.00
...

我需要将数据转换成这样:

prod_codigo  esps_fecini   Bins
1077         2018-11-12    200.00
1077         2018-11-13    200.00
1077         2018-11-14    250.00
1077         2018-11-15    250.00
1077         2018-11-16    0.00
1077         2018-11-17    0.00
1077         2018-11-18    0.00
...

我怎样才能做到这一点?

我正在使用以下查询,但找不到对日期求和的方法。我正在使用 SQL Server 2008

select prod_codigo,esps_fecini,U.Bins
from dba.estimprodsemana
unpivot
(
Bins
for datos in (esps_cadia1,esps_cadia2,esps_cadia3,esps_cadia4,esps_cadia5,esps_cadia6,esps_cadia7)
) U

您可以使用 APPLY 代替:

select e.prod_codigo, ee.*
from dba.estimprodsemana e cross apply
     ( values (esps_fecini, day1),
              (dateadd(day, 1, esps_fecini), day2),
              (dateadd(day, 2, esps_fecini), day3),
              (dateadd(day, 3, esps_fecini), day3),
              (dateadd(day, 4, esps_fecini), day4),
              (dateadd(day, 5, esps_fecini), day5),
              (dateadd(day, 6, esps_fecini), day6),
              (dateadd(day, 7, esps_fecini), day7)
     ) ee (esps_fecini, Bins);

你的问题已经有了答案,只是稍微格式化一下:)

此外,在这种情况下,您需要根据自然顺序使用 ROW_NUMBER() 推导偏移量。然后,您可以根据基于列顺序 D1..D7.

的应用派生字段计算日期
DECLARE @T TABLE(ID INT, Date DATETIME, D1 INT, D2 INT, D3 INT, D4 INT, D5 INT, D6 INT, D7 INT)
INSERT @T VALUES(1077,'11/12/2018',200,200,250,250,0,0,0)


SELECT
    ID,
    Date = DATEADD(DAY,DayNumber,Date),
    Bins    
FROM
(
    SELECT 
        ID,
        Date,
        Bins,
        DayNumber = ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ID) - 1
    FROM @T
    UNPIVOT
    (
        Bins FOR Dates in (D1,D2,D3,D4,D5,D6,D7)
    ) AS X
)AS Y

如果你想unpivot这个查询,你可以这样做:

declare @t table (prod_codigo int,esps_fecini date,day1 decimal(5,2),day2 decimal(5,2),
                  day3 decimal(5,2),day4 decimal(5,2),day5 decimal(5,2),day6 decimal(5,2),
                  day7 decimal(5,2))
insert into @t(prod_codigo,esps_fecini,day1,day2,day3,day4,day5,day6,day7) values
(1077,'20181112',200.00,200.00,250.00,250.00,0.00,0.00,0.00)

select
    prod_codigo,
    newDay,
    Value
from
    @t
        unpivot
    (Value for Offset in (day1,day2,day3,day4,day5,day6,day7)) u
        cross apply
    (select DATEADD(day,CONVERT(int,SUBSTRING(Offset,4,1))-1,esps_fecini) as newDay) v

我们首先 unpivot 然后找出如何从生成的 数据 (而不是元数据 - 列名)中提取可用数字来调整日期值。

结果:

prod_codigo newDay     Value
----------- ---------- ---------------------------------------
1077        2018-11-12 200.00
1077        2018-11-13 200.00
1077        2018-11-14 250.00
1077        2018-11-15 250.00
1077        2018-11-16 0.00
1077        2018-11-17 0.00
1077        2018-11-18 0.00

如果您的天数列多于您想要编码或指定的数量,或者如果天数列的数量是可变的,则以下将 "dynamically" 逆透视您的数据而不实际使用动态 SQL。

显然 UNPIVOT 会更高效

例子

declare @YourTable table (prod_codigo int,esps_fecini date,day1 decimal(5,2),day2 decimal(5,2),day3 decimal(5,2),day4 decimal(5,2),day5 decimal(5,2),day6 decimal(5,2),day7 decimal(5,2))
insert into @YourTable values
(1077,'20181112',200.00,200.00,250.00,250.00,0.00,0.00,0.00)


Select A.prod_codigo
      ,esps_fecini = dateadd(day,-1+replace(Item,'day',''),esps_fecini)
      ,Bins=C.Value
 From @YourTable A
 Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
 Cross Apply (
                Select Item = a.value('local-name(.)','varchar(100)')
                      ,Value = a.value('.','decimal(5,2)') 
                 From  B.XMLData.nodes('/row')  as C1(n)
                 Cross Apply C1.n.nodes('./@*') as C2(a)
                 Where a.value('local-name(.)','varchar(100)') like  'day%'
             ) C

Returns

prod_codigo esps_fecini Bins
1077        2018-11-12  200.00
1077        2018-11-13  200.00
1077        2018-11-14  250.00
1077        2018-11-15  250.00
1077        2018-11-16  0.00
1077        2018-11-17  0.00
1077        2018-11-18  0.00