[转]扣除节假日高效算法
转自:edobnet
在日常开发中,有时候需要扣除节假日,本人实际开发中使用了一套比较好的办法与大家讨论.
表结构ER设计如下:
其中:节假日表,是存计算好的节假日结果.并且把日期换成"整形日期",建立索引提高判断速度,
只要节假日,变成,当晚就可以通过DTS最新计算节假日表,
存储过程如下:
 CREATE   Procedure sp_holiday
CREATE   Procedure sp_holiday @YEAR int
    @YEAR int AS
AS --产生节假日数据
    --产生节假日数据 --exec sp_holiday 2005
    --exec sp_holiday 2005 SET NOCOUNT ON
    SET NOCOUNT ON 
     --判断是否需要计算
    --判断是否需要计算 IF (SELECT SET_IS_REDO FROM TJ_SETTINGS WHERE SET_YEAR = @YEAR) = 1
    IF (SELECT SET_IS_REDO FROM TJ_SETTINGS WHERE SET_YEAR = @YEAR) = 1 BEGIN
    BEGIN 
     BEGIN TRAN
        BEGIN TRAN 
         DELETE FROM TJ_HOLIDAY WHERE HOL_YEAR = @YEAR
        DELETE FROM TJ_HOLIDAY WHERE HOL_YEAR = @YEAR DECLARE @SQL VARCHAR(100), @THIS_DATE SMALLDATETIME, @BEGIN_DATE SMALLDATETIME, @END_DATE SMALLDATETIME, @HOL_NAME VARCHAR(50), @INDEX TINYINT, @IS_WEEK TINYINT
        DECLARE @SQL VARCHAR(100), @THIS_DATE SMALLDATETIME, @BEGIN_DATE SMALLDATETIME, @END_DATE SMALLDATETIME, @HOL_NAME VARCHAR(50), @INDEX TINYINT, @IS_WEEK TINYINT --初始化双休日数据
        --初始化双休日数据 CREATE TABLE #WEEK (WEEK_DAY TINYINT PRIMARY KEY NOT NULL, IS_WEEK TINYINT NULL)
        CREATE TABLE #WEEK (WEEK_DAY TINYINT PRIMARY KEY NOT NULL, IS_WEEK TINYINT NULL) SET @INDEX = 0
        SET @INDEX = 0 WHILE (@INDEX < 7)
        WHILE (@INDEX < 7) BEGIN
        BEGIN SET @SQL = 'INSERT INTO #WEEK (WEEK_DAY, IS_WEEK) SELECT ' + CAST(@INDEX AS CHAR(1)) + ', WK_' + CAST(@INDEX AS CHAR(1)) + ' FROM TJ_WEEK WHERE WK_YEAR = ' + CAST(@YEAR AS CHAR(4))
            SET @SQL = 'INSERT INTO #WEEK (WEEK_DAY, IS_WEEK) SELECT ' + CAST(@INDEX AS CHAR(1)) + ', WK_' + CAST(@INDEX AS CHAR(1)) + ' FROM TJ_WEEK WHERE WK_YEAR = ' + CAST(@YEAR AS CHAR(4)) EXEC(@SQL)
            EXEC(@SQL) SET @INDEX = @INDEX + 1
            SET @INDEX = @INDEX + 1 END
        END --每一天判断
        --每一天判断 SET @BEGIN_DATE = CONVERT(SMALLDATETIME, CAST(@YEAR AS CHAR(4)) + '-01-01', 120)
        SET @BEGIN_DATE = CONVERT(SMALLDATETIME, CAST(@YEAR AS CHAR(4)) + '-01-01', 120) SET @END_DATE = DATEADD(YEAR, 1, @BEGIN_DATE)
        SET @END_DATE = DATEADD(YEAR, 1, @BEGIN_DATE) SET @THIS_DATE = @BEGIN_DATE
        SET @THIS_DATE = @BEGIN_DATE WHILE (@THIS_DATE < @END_DATE)
        WHILE (@THIS_DATE < @END_DATE) BEGIN
        BEGIN --非节假日
            --非节假日 IF EXISTS (SELECT * FROM TJ_NONFERIA WHERE NFR_YEAR = @YEAR AND NFR_DATE = @THIS_DATE)
            IF EXISTS (SELECT * FROM TJ_NONFERIA WHERE NFR_YEAR = @YEAR AND NFR_DATE = @THIS_DATE) begin
            begin SET @THIS_DATE = DATEADD(DAY, 1, @THIS_DATE)
                SET @THIS_DATE = DATEADD(DAY, 1, @THIS_DATE) CONTINUE
                CONTINUE end
            end --节日
            --节日 ELSE IF EXISTS (SELECT * FROM TJ_FERIA WHERE FER_YEAR = @YEAR AND FER_DATE = @THIS_DATE)
            ELSE IF EXISTS (SELECT * FROM TJ_FERIA WHERE FER_YEAR = @YEAR AND FER_DATE = @THIS_DATE) BEGIN
            BEGIN SELECT @HOL_NAME = FER_NAME FROM TJ_FERIA WHERE FER_YEAR = @YEAR AND FER_DATE = @THIS_DATE
                SELECT @HOL_NAME = FER_NAME FROM TJ_FERIA WHERE FER_YEAR = @YEAR AND FER_DATE = @THIS_DATE INSERT INTO TJ_HOLIDAY (HOL_YEAR, HOL_DATE_INT, HOL_DATE, HOL_NAME)
                INSERT INTO TJ_HOLIDAY (HOL_YEAR, HOL_DATE_INT, HOL_DATE, HOL_NAME)  VALUES (@YEAR, FLOOR(CONVERT(FLOAT, @THIS_DATE)), @THIS_DATE, @HOL_NAME)
                VALUES (@YEAR, FLOOR(CONVERT(FLOAT, @THIS_DATE)), @THIS_DATE, @HOL_NAME) END
            END --休息日
            --休息日 ELSE
            ELSE BEGIN
            BEGIN SELECT @IS_WEEK = IS_WEEK FROM #WEEK WHERE WEEK_DAY = (DATEPART(WEEKDAY, @THIS_DATE) - 1)
                SELECT @IS_WEEK = IS_WEEK FROM #WEEK WHERE WEEK_DAY = (DATEPART(WEEKDAY, @THIS_DATE) - 1) IF (@IS_WEEK > 0)
                IF (@IS_WEEK > 0) INSERT INTO TJ_HOLIDAY (HOL_YEAR, HOL_DATE_INT, HOL_DATE, HOL_NAME)
                    INSERT INTO TJ_HOLIDAY (HOL_YEAR, HOL_DATE_INT, HOL_DATE, HOL_NAME)  VALUES (@YEAR, FLOOR(CONVERT(FLOAT, @THIS_DATE)), @THIS_DATE, DATENAME(WEEKDAY, @THIS_DATE))
                    VALUES (@YEAR, FLOOR(CONVERT(FLOAT, @THIS_DATE)), @THIS_DATE, DATENAME(WEEKDAY, @THIS_DATE)) END
            END SET @THIS_DATE = DATEADD(DAY, 1, @THIS_DATE)
            SET @THIS_DATE = DATEADD(DAY, 1, @THIS_DATE) END
        END 
         --重新设置计算标记
        --重新设置计算标记 UPDATE TJ_SETTINGS SET SET_IS_REDO = 0 WHERE SET_YEAR = @YEAR
        UPDATE TJ_SETTINGS SET SET_IS_REDO = 0 WHERE SET_YEAR = @YEAR 
         IF @@ERROR = 0
        IF @@ERROR = 0 COMMIT TRAN
            COMMIT TRAN ELSE
        ELSE  ROLLBACK TRAN
            ROLLBACK TRAN 
         DROP TABLE #WEEK
        DROP TABLE #WEEK 
     END
    END 
     SET NOCOUNT OFF
    SET NOCOUNT OFF
 GO
GO
外
 /******************************************************************
/****************************************************************** * 名称: 工作日重新
* 名称: 工作日重新 * 作者: WANGYJ<edobnet@hotmail.com>
* 作者: WANGYJ<edobnet@hotmail.com> * 时间: 2005-5-17
* 时间: 2005-5-17 *
* * -----------------------------------------------------------------
* ----------------------------------------------------------------- * 版本        时间            作者        备注
* 版本        时间            作者        备注 *
* * V1.00        2005-5-3    WANGYJ        创建
* V1.00        2005-5-3    WANGYJ        创建 * -----------------------------------------------------------------
* ----------------------------------------------------------------- ******************************************************************/
******************************************************************/ create  Procedure sp_holiday_ALL
create  Procedure sp_holiday_ALL 
     AS
AS DECLARE my_cursor CURSOR for
    DECLARE my_cursor CURSOR for select SET_YEAR from TJ_SETTINGS  where SET_IS_REDO = 1
    select SET_YEAR from TJ_SETTINGS  where SET_IS_REDO = 1 DECLARE @year varchar(4)
    DECLARE @year varchar(4) 
     open my_cursor
    open my_cursor FETCH NEXT FROM my_cursor
    FETCH NEXT FROM my_cursor  INTO @year
    INTO @year WHILE @@FETCH_STATUS = 0
WHILE @@FETCH_STATUS = 0 BEGIN
BEGIN exec risk.sp_holiday @year
    exec risk.sp_holiday @year 
   FETCH NEXT FROM my_cursor
    FETCH NEXT FROM my_cursor  INTO @year
    INTO @year 
        END
END CLOSE my_cursor
   CLOSE my_cursor DEALLOCATE my_cursor
   DEALLOCATE my_cursor
 GO
GO
节假日扣除函数如下:



 CREATE    FUNCTION risk.CalcDay
CREATE    FUNCTION risk.CalcDay (
( @Diff smallint,        --差别值.正数为加,负数减
    @Diff smallint,        --差别值.正数为加,负数减 @D_Date datetime      --差别日期
    @D_Date datetime      --差别日期 )
) RETURNS datetime
RETURNS datetime AS
AS BEGIN
    BEGIN declare @ordDate datetime
        declare @ordDate datetime set @ordDate = @D_Date
        set @ordDate = @D_Date set @D_Date = convert(char(10), @D_Date, 120)  --去掉时间部分(防止传入的参数中有时间部分,影响处理)
        set @D_Date = convert(char(10), @D_Date, 120)  --去掉时间部分(防止传入的参数中有时间部分,影响处理) if @Diff > 0
        if @Diff > 0 begin
        begin while @Diff > 0
            while @Diff > 0 begin
            begin select @D_Date = @D_Date + @Diff, @Diff = count(*) from TJ_HOLIDAY
                select @D_Date = @D_Date + @Diff, @Diff = count(*) from TJ_HOLIDAY  where HOL_DATE_INT > FLOOR(CONVERT(FLOAT, @D_Date)) AND HOL_DATE_INT <= FLOOR(CONVERT(FLOAT, @D_Date + @Diff))
                where HOL_DATE_INT > FLOOR(CONVERT(FLOAT, @D_Date)) AND HOL_DATE_INT <= FLOOR(CONVERT(FLOAT, @D_Date + @Diff)) end
            end end
        end else
        else begin
        begin while @Diff < 0
            while @Diff < 0 begin
            begin select @D_Date = @D_Date + @Diff, @Diff =- count(*) from TJ_HOLIDAY
                select @D_Date = @D_Date + @Diff, @Diff =- count(*) from TJ_HOLIDAY  where HOL_DATE_INT < FLOOR(CONVERT(FLOAT, @D_Date)) AND HOL_DATE_INT >= FLOOR(CONVERT(FLOAT, @D_Date + @Diff))
                where HOL_DATE_INT < FLOOR(CONVERT(FLOAT, @D_Date)) AND HOL_DATE_INT >= FLOOR(CONVERT(FLOAT, @D_Date + @Diff)) end
            end end
        end set @D_Date = dateadd(hour,datepart(hour,@ordDate),@D_Date)
    set @D_Date = dateadd(hour,datepart(hour,@ordDate),@D_Date) set @D_Date = dateadd(minute,datepart(minute,@ordDate),@D_Date)
    set @D_Date = dateadd(minute,datepart(minute,@ordDate),@D_Date) set @D_Date = dateadd(second,datepart(second,@ordDate),@D_Date)
    set @D_Date = dateadd(second,datepart(second,@ordDate),@D_Date) return(@D_Date)
    return(@D_Date) END
    END





这样就可以使用了,dbo.CaclDay(-5,getdate())就是扣除节假以后的5天前的数据
希望对大家有帮助
 
                    
                     
                    
                 
                    
                
 

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号