Reputation: 1061
I have a table with sample like this:
In this example there are Day1, Day2, and Day3 but in the real data it could be Day1 through Day100.
How can I sum the data in the row for a particular range like Day1 through Day3 or Day2 through Day10 for TSTID = 1?
Upvotes: 1
Views: 120
Reputation: 82020
This approach is a little more dynamic, without actually being dynamic. Notice that we don't have to specify or dynamically create the field list.
Declare @YourTable table (TSTID int,Year int,Day1 int,Day2 int,Day3 int)
Insert Into @YourTable values
(1,2015,1000,4000,7000),
(2,2015,2000,5000,8000),
(3,2015,3000,6000,9000)
Declare @DayR1 int = 1
Declare @DayR2 int = 3
Select A.TSTID
,TotalSum = sum(B.Value)
From @YourTable A
Cross Apply (Select Value=cast(value as int)
From [dbo].[udf-EAV]((Select A.* for XML RAW))
Where Attribute Like 'Day%'
and cast(Replace(Attribute,'Day','') as int) between 1 and 3
) B
Where A.TSTID = 1
Group By A.TSTID
Returns
TSTID TotalSum
1 12000
Now, I do use a helper function here. It is a TVF which converts virtually any dataset into an EAV structure (Entity Attribute Value). CLEARLY UNPIVOT would perform better with LARGER datasets.
I should add, that if you don't want the function, the logic can easily be ported into the CROSS APPLY
CREATE FUNCTION [dbo].[udf-EAV](@XML xml)
Returns Table
As
Return (
with cteKey(k) as (Select Top 1 xAtt.value('local-name(.)','varchar(100)') From @XML.nodes('/row') As A(xRow) Cross Apply A.xRow.nodes('./@*') As B(xAtt))
Select Entity = xRow.value('@*[1]','varchar(50)')
,Attribute = xAtt.value('local-name(.)','varchar(100)')
,Value = xAtt.value('.','varchar(max)')
From @XML.nodes('/row') As A(xRow)
Cross Apply A.xRow.nodes('./@*') As B(xAtt)
Where xAtt.value('local-name(.)','varchar(100)') Not In (Select k From cteKey)
)
-- Notes: First Field in Query will be the Entity
-- Select * From [dbo].[udf-EAV]((Select UTCDate=GetUTCDate(),* From sys.dm_os_sys_info for XML RAW))
Upvotes: 1