计算自给定日期以来经过的月份中特定日期的数量

时间:2016-11-11 19:13:54

标签: sql-server tsql sql-server-2012

我正在SQL Server 2012中编写一个函数,该函数需要知道自给定日期以来已过去的3个特定日期的数量。我可以用一个while循环来做这个,但它很慢,我正在寻找一个更好的方法。 以下是我到目前为止的情况:

  

我们假设GETDATE()= '11 / 14/2016'和@productDate = '10 / 1/2016'

    --Get the number of "units" that have passed since the date on the label
DECLARE @unitCount INT = 0;
DECLARE @countingDate DATE 
SET @countingDate = DATEADD(DAY,1,@productDate);--add 1 to prevent counting the date on the label as the first unit
WHILE (@countingDate < CAST(GETDATE() As date ))
    BEGIN
        SELECT @unitCount = @unitCount + 
            CASE
                WHEN DAY(@countingDate) = 1 OR DAY(@countingDate) = 10 OR DAY(@countingDate) = 20 THEN 1
                ELSE 0
            END
        SET @countingDate = DATEADD(DAY,1,@countingDate);
    END 
  

这将导致@unitCount = 4

     <11> '11 / 20/2016'的GETDATE()将导致@unitCount = 5

2 个答案:

答案 0 :(得分:2)

不使用数字表

create function dbo.fn_DateCounter
(
    @datefrom date,
    @dateto date
)
returns int 
as 
begin
    return 
    -- number of complete months
    3 * 
    (
        (DATEPART(YYYY, @dateto) * 12 + DATEPART(MM, @dateto)) 
        -(DATEPART(YYYY, @datefrom) * 12 + DATEPART(MM, @datefrom))      
        - 1
    )
    -- add on the extras from the first month
    + case when DATEPART(DD, @datefrom) < 10 then 2
           when DATEPART(DD, @datefrom) < 20 then 1
           else 0
    end
    -- add on the extras from the last month
    + case when DATEPART(DD, @dateto) > 20 then 3
           when DATEPART(DD, @dateto) > 10 then 2
           else 1 
    end

end
go

select dbo.fn_DateCounter('01-jan-2000','01-jan-2000') -- 0 
select dbo.fn_DateCounter('01-jan-2000','10-jan-2000') -- 0 
select dbo.fn_DateCounter('01-jan-2000','11-jan-2000') -- 1
select dbo.fn_DateCounter('01-jan-2000','20-jan-2000') -- 1
select dbo.fn_DateCounter('01-jan-2000','21-jan-2000') -- 2
select dbo.fn_DateCounter('11-jan-2000','21-jan-2000') -- 1
select dbo.fn_DateCounter('11-jan-2000','21-feb-2000') -- 4
select dbo.fn_DateCounter('01-jan-2000','01-jan-2001') -- 36
select dbo.fn_DateCounter('01-jan-2000','11-jan-2001') -- 37

答案 1 :(得分:1)

您可以结合使用sumcasedbo.spt_values表:

declare @productDate datetime = '11/01/2016',
    @unitCount int

;with nums as ( -- use a CTE to build a number list
    select top 1000 number from master..spt_values
)

select  @unitCount = sum( 
            case    when day(dateadd(day, n, @productDate)) in (1, 10, 20) 
                    then 1 else 0 end
    ) -- add 1 for each 1,10,20 we find
from (
    select  n = row_number() over (order by nums.number)
    from    nums cross join nums as num -- 1000*1000 = 1 million rows
) n
where   dateadd(day, n, @productDate) < getdate()

select  @unitCount

这将获取@productDategetdate()之间的每个日期。对于每1/10/20,case语句将select 1,对于每个其他日期,{0}将为0。最后,我们取结果的sum

对于11/1 - 11/11,它返回1。 对于1/1 - 11/11,结果为31。

编辑:在CTE(with nums as...)中,我们选择1-1000,然后我们执行cross join,这为我们提供了一百万条记录。答案仍然有限,但现在你可以用2700年了。