Я также создал функцию для этого.
Однако, когда функция применяется к большому набору, лучше переместить функцию к реальному запросу, чем использовать функцию.
/*
Yearfrac
Purpose: calculate the fraction of years between start_date and end_date
Code Actual/actual is translated from VBA code Excel formula YearFrac
Basis Day count basis
0 or omitted US (NASD) 30/360
1 Actual/actual
2 Actual/360
3 Actual/365
4 European 30/360
*/
ALTER FUNCTION [obm].[fn_YearFrac]
(
@Start_date DATE
, @End_date DATE
, @Basis INT
)
RETURNS DECIMAL(18, 10)
AS
BEGIN
DECLARE @YearFrac DECIMAL(18, 10)
;
if @Basis = 1
begin
SELECT @YearFrac =
datediff(d, @Start_date, @End_date) /
case when -- Scenario 1: Jaar start = Jaar eind
year(@Start_date) = year(@End_date)
then
a.aantal_dagen
when -- Scenario 2: Kalenderjaar van eiddatum is 1 jaar na kalenderjaar startdatum
year(@End_date) - year(@Start_date) = 1
then
b.aantal_dagen
when -- Scenario 3: Kalenderjaar van eiddatum is meer dan 1 jaar na kalenderjaar startdatum
year(@End_date) - year(@Start_date) > 1
then
(c.aantal_dagen/c.aantal_jaar)
else null
end
from (select @Start_date dat_start, @End_date dat_end) src
cross apply (select cast ( COUNT(nbr_jaar) as decimal(18,10) ) aantal_dagen from dbo.dim_datum icd where icd.nbr_jaar = year(src.dat_start)) a
cross apply (select cast ( COUNT(nbr_jaar) + 365 as decimal(18,10) ) aantal_dagen from dbo.dim_datum icd where nbr_maand = 2 and nbr_dag_in_maand = 29 and cast( dat_datum as date ) between dat_start and dat_end) b
cross apply (select cast ( COUNT(nbr_jaar) as decimal(18,10) ) aantal_dagen, count(distinct nbr_jaar) aantal_jaar from dbo.dim_datum icd where nbr_jaar between year(dat_start) and year(dat_end) ) c
end
if @Basis = 2
begin
SELECT @YearFrac = DATEDIFF (d, @start_date, @end_date) / 360.00
end
if @Basis = 3
begin
SELECT @YearFrac = DATEDIFF (d, @start_date, @end_date) / 365.00
end
RETURN
@YearFrac;
END;