richard
richard

Reputation: 12526

Find percentage of year covered in period (month) range?

Given a table of structure:

CREATE TABLE [dbo].[Example](  
    [FiscalYear] INT NOT NULL,  
    [Hours] [decimal](28, 2) NULL,  
    CONSTRAINT [PK_Example] PRIMARY KEY CLUSTERED (
        [FiscalYear] ASC  
    )
    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
        ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

with data

INSERT INTO [Example] ([FiscalYear], [Hours]) VALUES (2009 ,25) GO 
INSERT INTO [Example] ([FiscalYear], [Hours]) VALUES (2010 ,20) GO
INSERT INTO [Example] ([FiscalYear], [Hours]) VALUES (2011 ,30)

Assuming we provide a date range in periods (i.e. March 2010 is expressed as 201003) for instance @StartPeriod = 201009, @EndPeriod = 201108

How would I query table Example so that I get representative data for the periods covered in the date range.

In the case with the date range given above, we would get:

(.33333*25) + (.66666*30) = 26.66666

Where .33333 is because 2010 has only 4 months (1/3 of the total year) represented in the period date range, and .66666 is because 2011 has 8 months (2/3 of the total year) represented in the period date range.

How do I write a query to get those representative "weights"? Also assume that in some cases a date range could span multiple years i.e. @StartPeriod = 200905, @EndPeriod = 201104 in which case 2010 would be represented by 100% (1).

Upvotes: 3

Views: 476

Answers (1)

Andomar
Andomar

Reputation: 238246

You can build a list of all months in a CTE. Matching months contribute 1/12th of the yearly number of hours. You can use an inner join to add up only the matching months:

; with  AllMonths as
        (
        select  cast('2001-01-01' as datetime) as MonthStart
        union all
        select  dateadd(month, 1, MonthStart)
        from    AllMonths
        where   MonthStart < '2020-01-01'
        )
select  sum(e.Hours/12)
from    AllMonths am
join    @example e
on      e.FiscalYear = datepart(year, am.MonthStart)
where   am.MonthStart between '2010-09-01' and '2011-08-01'
option  (maxrecursion 0)

The result is 4/12*20+8/12*30 = 26.66. Your example answer was 21.66 because it uses 20 as the number of hours for 2011. THis answer is using 30 per the dataset.

Working example at SE Data.

Upvotes: 3

Related Questions