Sql 2005中的YearFrac

时间:2009-07-10 17:23:49

标签: sql excel

如何在Sql 2005中编写Excel附带的YearFrac函数?

4 个答案:

答案 0 :(得分:5)

使用DateDiff找出两个日期之间的距离,然后将该值除以365

修改

当然,您可以创建自己的功能来完成这项工作:

create function yearfrac (@d1 datetime, @d2 datetime) returns float
as
begin
return abs(datediff(d, @d1, @d2)) / 365.00
end

答案 1 :(得分:3)

对于默认用法(两个数据参数):

datediff(day, date1, date2) / 360.0

对于第三个参数值为3的特殊情况:

datediff(day, date1, date2) / 365.0

编辑:
添加了一个小数,使其成为浮点运算。

答案 2 :(得分:0)

我还为此创建了一个函数。 但是,当将函数应用于大集合时,最好将函数移至实际查询,而不要使用函数。

/*
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;

答案 3 :(得分:-3)

我知道这是一个有点迟到的回应,但万一其他人偶然发现这是我做过的事情:

CREATE FUNCTION dbo.udfYearFrac
(
    @StartDate  AS DATETIME,
    @EndDate    AS DATETIME
)
RETURNS DECIMAL(18,6)
AS
BEGIN
    DECLARE @YearFrac       AS DECIMAL(18,6)
    DECLARE @nbDaysInPeriod AS INT 
    DECLARE @nbYears        AS INT

    SELECT 
        @nbDaysInPeriod = DATEDIFF(DAY, @StartDate, @EndDate) 
        ,@nbYears = YEAR(@EndDate) - YEAR(@StartDate) + 1

    SELECT @YearFrac = @nbDaysInPeriod /
        CASE WHEN YEAR(@StartDate) = YEAR(@EndDate) OR (YEAR(@EndDate)-1 = YEAR(@StartDate) AND (MONTH(@StartDate) > MONTH(@EndDate) OR MONTH(@StartDate) = MONTH(@EndDate) AND (DAY(@StartDate) >= DAY(@EndDate)))) 
        THEN
            CASE WHEN YEAR(@StartDate) = YEAR(@EndDate) AND ISDATE(CAST(YEAR(@StartDate) AS CHAR(4)) + '0229') = 1 
            THEN 366.0
            ELSE
                CASE WHEN DAY(@EndDate) = 29 AND MONTH(@EndDate) = 2
                THEN 366.0
                ELSE
                    CASE WHEN ISDATE(CAST(YEAR(@StartDate) AS CHAR(4)) + '0229') = 1
                    THEN
                        CASE WHEN (@StartDate <= cast('2/29/' + cast(YEAR(@StartDate) AS CHAR(4)) AS DATETIME) AND cast('2/29/' + cast(YEAR(@StartDate) AS CHAR(4)) AS DATETIME) <= @EndDate) 
                        THEN 366.0 
                        ELSE 365.0
                        END
                    ELSE
                        CASE WHEN ISDATE(CAST(YEAR(@EndDate) AS CHAR(4)) + '0229') = 1
                        THEN
                            CASE WHEN (@StartDate <= cast('2/29/' + cast(YEAR(@EndDate) AS CHAR(4)) AS DATETIME) AND cast('2/29/' + cast(YEAR(@EndDate) AS CHAR(4)) AS DATETIME) <= @EndDate) 
                            THEN 366.0 
                            ELSE 365.0 
                            END
                        ELSE 365.0
                        END
                    END
                END
            END
        ELSE
            ((@nbYears * 365.0) +
                (
                    SELECT COUNT(*) FROM 
                    (
                        SELECT (ROW_NUMBER() OVER(ORDER BY TABLE_NAME ASC) - 1) * 4 + 1900 AS [YEAR] 
                        FROM INFORMATION_SCHEMA.COLUMNS
                    ) yr
                    WHERE [YEAR] BETWEEN YEAR(@StartDate) AND YEAR(@EndDate) 
                )
            ) / @nbYears
        END
    RETURN @YearFrac
END