扣除节假日高效算法
2005-08-21 18:01
573 查看
在日常开发中,有时候需要扣除节假日,本人实际开发中使用了一套比较好的办法与大家讨论.
表结构ER设计如下:
CREATE Procedure sp_holiday
@YEAR int
AS
--产生节假日数据
--exec sp_holiday 2005
SET NOCOUNT ON
--判断是否需要计算
IF (SELECT SET_IS_REDO FROM TJ_SETTINGS WHERE SET_YEAR = @YEAR) = 1
BEGIN
BEGIN TRAN
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
--初始化双休日数据
CREATE TABLE #WEEK (WEEK_DAY TINYINT PRIMARY KEY NOT NULL, IS_WEEK TINYINT NULL)
SET @INDEX = 0
WHILE (@INDEX < 7)
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))
EXEC(@SQL)
SET @INDEX = @INDEX + 1
END
--每一天判断
SET @BEGIN_DATE = CONVERT(SMALLDATETIME, CAST(@YEAR AS CHAR(4)) + '-01-01', 120)
SET @END_DATE = DATEADD(YEAR, 1, @BEGIN_DATE)
SET @THIS_DATE = @BEGIN_DATE
WHILE (@THIS_DATE < @END_DATE)
BEGIN
--非节假日
IF EXISTS (SELECT * FROM TJ_NONFERIA WHERE NFR_YEAR = @YEAR AND NFR_DATE = @THIS_DATE)
begin
SET @THIS_DATE = DATEADD(DAY, 1, @THIS_DATE)
CONTINUE
end
--节日
ELSE IF EXISTS (SELECT * FROM TJ_FERIA WHERE FER_YEAR = @YEAR AND FER_DATE = @THIS_DATE)
BEGIN
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)
VALUES (@YEAR, FLOOR(CONVERT(FLOAT, @THIS_DATE)), @THIS_DATE, @HOL_NAME)
END
--休息日
ELSE
BEGIN
SELECT @IS_WEEK = IS_WEEK FROM #WEEK WHERE WEEK_DAY = (DATEPART(WEEKDAY, @THIS_DATE) - 1)
IF (@IS_WEEK > 0)
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))
END
SET @THIS_DATE = DATEADD(DAY, 1, @THIS_DATE)
END
--重新设置计算标记
UPDATE TJ_SETTINGS SET SET_IS_REDO = 0 WHERE SET_YEAR = @YEAR
IF @@ERROR = 0
COMMIT TRAN
ELSE
ROLLBACK TRAN
DROP TABLE #WEEK
END
SET NOCOUNT OFF
GO
外
create Procedure sp_holiday_ALL
AS
DECLARE my_cursor CURSOR for
select SET_YEAR from TJ_SETTINGS where SET_IS_REDO = 1
DECLARE @year varchar(4)
open my_cursor
FETCH NEXT FROM my_cursor
INTO @year
WHILE @@FETCH_STATUS = 0
BEGIN
exec risk.sp_holiday @year
FETCH NEXT FROM my_cursor
INTO @year
END
CLOSE my_cursor
DEALLOCATE my_cursor
GO
节假日扣除函数如下:
CREATE FUNCTION risk.CalcDay
(
@Diff smallint, --差别值.正数为加,负数减
@D_Date datetime --差别日期
)
RETURNS datetime
AS
BEGIN
declare @ordDate datetime
set @ordDate = @D_Date
set @D_Date = convert(char(10), @D_Date, 120) --去掉时间部分(防止传入的参数中有时间部分,影响处理)
if @Diff > 0
begin
while @Diff > 0
begin
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))
end
end
else
begin
while @Diff < 0
begin
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))
end
end
set @D_Date = dateadd(hour,datepart(hour,@ordDate),@D_Date)
set @D_Date = dateadd(minute,datepart(minute,@ordDate),@D_Date)
set @D_Date = dateadd(second,datepart(second,@ordDate),@D_Date)
return(@D_Date)
END
这样就可以使用了,dbo.CaclDay(-5,getdate())就是扣除节假以后的5天前的数据
希望对大家有帮助
表结构ER设计如下:
CREATE Procedure sp_holiday
@YEAR int
AS
--产生节假日数据
--exec sp_holiday 2005
SET NOCOUNT ON
--判断是否需要计算
IF (SELECT SET_IS_REDO FROM TJ_SETTINGS WHERE SET_YEAR = @YEAR) = 1
BEGIN
BEGIN TRAN
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
--初始化双休日数据
CREATE TABLE #WEEK (WEEK_DAY TINYINT PRIMARY KEY NOT NULL, IS_WEEK TINYINT NULL)
SET @INDEX = 0
WHILE (@INDEX < 7)
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))
EXEC(@SQL)
SET @INDEX = @INDEX + 1
END
--每一天判断
SET @BEGIN_DATE = CONVERT(SMALLDATETIME, CAST(@YEAR AS CHAR(4)) + '-01-01', 120)
SET @END_DATE = DATEADD(YEAR, 1, @BEGIN_DATE)
SET @THIS_DATE = @BEGIN_DATE
WHILE (@THIS_DATE < @END_DATE)
BEGIN
--非节假日
IF EXISTS (SELECT * FROM TJ_NONFERIA WHERE NFR_YEAR = @YEAR AND NFR_DATE = @THIS_DATE)
begin
SET @THIS_DATE = DATEADD(DAY, 1, @THIS_DATE)
CONTINUE
end
--节日
ELSE IF EXISTS (SELECT * FROM TJ_FERIA WHERE FER_YEAR = @YEAR AND FER_DATE = @THIS_DATE)
BEGIN
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)
VALUES (@YEAR, FLOOR(CONVERT(FLOAT, @THIS_DATE)), @THIS_DATE, @HOL_NAME)
END
--休息日
ELSE
BEGIN
SELECT @IS_WEEK = IS_WEEK FROM #WEEK WHERE WEEK_DAY = (DATEPART(WEEKDAY, @THIS_DATE) - 1)
IF (@IS_WEEK > 0)
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))
END
SET @THIS_DATE = DATEADD(DAY, 1, @THIS_DATE)
END
--重新设置计算标记
UPDATE TJ_SETTINGS SET SET_IS_REDO = 0 WHERE SET_YEAR = @YEAR
IF @@ERROR = 0
COMMIT TRAN
ELSE
ROLLBACK TRAN
DROP TABLE #WEEK
END
SET NOCOUNT OFF
GO
外
create Procedure sp_holiday_ALL
AS
DECLARE my_cursor CURSOR for
select SET_YEAR from TJ_SETTINGS where SET_IS_REDO = 1
DECLARE @year varchar(4)
open my_cursor
FETCH NEXT FROM my_cursor
INTO @year
WHILE @@FETCH_STATUS = 0
BEGIN
exec risk.sp_holiday @year
FETCH NEXT FROM my_cursor
INTO @year
END
CLOSE my_cursor
DEALLOCATE my_cursor
GO
节假日扣除函数如下:
CREATE FUNCTION risk.CalcDay
(
@Diff smallint, --差别值.正数为加,负数减
@D_Date datetime --差别日期
)
RETURNS datetime
AS
BEGIN
declare @ordDate datetime
set @ordDate = @D_Date
set @D_Date = convert(char(10), @D_Date, 120) --去掉时间部分(防止传入的参数中有时间部分,影响处理)
if @Diff > 0
begin
while @Diff > 0
begin
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))
end
end
else
begin
while @Diff < 0
begin
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))
end
end
set @D_Date = dateadd(hour,datepart(hour,@ordDate),@D_Date)
set @D_Date = dateadd(minute,datepart(minute,@ordDate),@D_Date)
set @D_Date = dateadd(second,datepart(second,@ordDate),@D_Date)
return(@D_Date)
END
这样就可以使用了,dbo.CaclDay(-5,getdate())就是扣除节假以后的5天前的数据
希望对大家有帮助
相关文章推荐
- 算法竞赛入门经典:第八章 高效算法设计 8.9棋盘覆盖
- 紫书第八章-----高效算法设计(贪心法)
- 判断n以内的素数(高效算法)
- 问题描述如下: 有2.5亿个整数(这2.5亿个整数存储在一个数组里面,至于数组是放在外存还是内存,没有进一步具体说明); 要求找出这2.5亿个数字里面,不重复的数字的个数; 另外,可用的内存限定为600M; 要求算法尽量高效,最优;
- 高效简洁的字符串交换算法
- 【高效算法设计】UVa120 Stack of Flapjacks
- 一个非常高效的去重且保持原顺序算法
- 根据数据库表中记录自动构造一棵结构树的一种高效算法
- 【高效算法设计——双向扫描】 UVa 1442 Cave
- 高效算法——G - 贪心
- 13行代码实现最快速最高效的积分图像算法
- 构建FP-growth算法高效发现频繁项集
- 筛法:一种高效求解素数表的算法
- 算法竞赛入门经典:第八章 高效算法设计 8.3归并排序应用之逆序对数
- 高效的数据结构和经典算法
- 算法初步——其他高效技巧与算法
- 字符串元素重排高效算法集合
- 1-2-5组合问题的最高效完整算法
- A、B两个整数集合,设计一个算法求他们的交集,尽可能的高效。
- N皇后的最高效算法