Reputation: 477
I have the following data in a crosstable format:
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
...
I need to convert the data to something like this:
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
...
How can I achieve this?
I'm using the following query, but I can't find a way to sum the dates. I'm using 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
Upvotes: 0
Views: 1603
Reputation: 81970
If you have more day columns than you care to code or specify, or if the number of day columns is variable, the following will "dynamically" unpivot your data without actually using dynamic SQL.
Clearly UNPIVOT would be more performant
Example
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
Upvotes: 0
Reputation: 15175
You had the answer in your question, just a little formatting :)
Also, you need to derive the offset using ROW_NUMBER(), based on natural order, in this case. You can then calculate the date based on the applying th derived field based on column order 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
Upvotes: 0
Reputation: 239724
If you do want to unpivot
for this query, you can do it like this:
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
Where we unpivot
first and then work out how to extract a usable number from the resulting data (rather than metadata - the column names) to adjust the date value.
Result:
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
Upvotes: 2
Reputation: 50163
You can use APPLY
instead :
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);
Upvotes: 0