本文目錄列表:1、SQL Server旬時間粒度2、SQL Server月有關時間粒度3、SQL Server函數重構4、總結語5、參考清單列表SQL Server旬時間粒度 SQL Server不存在旬這個時間粒度,這個時間粒度在我們國家存在的。一個月分為上、中、下3旬,上旬和中旬均10天,分別對...
本文目錄列表: 1、SQL Server旬時間粒度
2、SQL Server月有關時間粒度 3、SQL Server函數重構 4、總結語 5、參考清單列表 SQL Server旬時間粒度 SQL Server不存在旬這個時間粒度,這個時間粒度在我們國家存在的。一個月分為上、中、下3旬,上旬和中旬均10天,分別對應第1天到第10天和第11天到第20天,下旬有可能8天、9天、10天和11天,從第21天到月末最後1天。從旬的定義得知旬是個日期時間範圍的,那麼如何實現將旬時間粒度時間值和一個對應的整數來實現相互轉換呢?從旬的定義得知每旬都有個開始日期的,這個日期我們就叫做旬基準日期。如果同一旬的任意一個日期都對應一個相同的整數,那麼再將一個整數轉換為一個旬基準日期,這樣我們可以實現旬基準日期和整數的相互轉換。我們還可以得到每個日期在所在旬的第幾天,也可以將得到一個月份每日期所在的旬索引(這個類似每周的任何一天對應的weekday值,從1到7分別對應星期一到星期日)。 提供獲得指定日期在當前月哪個旬的功能的函數,T-SQL代碼如下:
1 IF OBJECT_ID(N'dbo.ufn_PeriodOfMonth', 'FN') IS NOT NULL 2 BEGIN 3 DROP FUNCTION dbo.ufn_PeriodOfMonth; 4 END 5 GO 6 7 --================================== 8 -- 功能: 獲得指定日期時間在當前月的旬索引 9 -- 說明: 從1開始計數,1、2、3分別對應上、中、下的旬索引。 10 -- 作者: XXX 11 -- 創建: yyyy-MM-dd 12 -- 修改: yyyy-MM-dd XXX 修改內容描述 13 -- 調用: SET @intPeriods = dbo.ufn_PeriodOfMonth('2008-01-14') 14 --================================== 15 CREATE FUNCTION [dbo].[ufn_PeriodOfMonth] 16 ( 17 @dtmDate DATETIME -- 指定的日期時間 18 ) RETURNS TINYINT 19 --$Encode$-- 20 AS 21 BEGIN 22 --當前月的日索引,從1開始計數,,包括1、2、3、……、28、29、30、31 23 DECLARE @tintDayOfMonth AS TINYINT; 24 SET @tintDayOfMonth = DAY(@dtmDate); 25 -- 旬偏移索引,0:上旬,1:中旬,2:下旬 26 DECLARE @tintPeriodOffsetIndexID AS INT; 27 SET @tintPeriodOffsetIndexID = DAY(@dtmDate) / 10 28 29 IF @tintDayOfMonth IN (10, 20, 30, 31) 30 BEGIN 31 SET @tintPeriodOffsetIndexID = @tintPeriodOffsetIndexID - 1; 32 END 33 34 RETURN @tintPeriodOffsetIndexID + 1; 35 END 36 GOView Code
提供獲得指定日期在當前旬第幾天的功能函數,T-SQL代碼如下:
1 IF OBJECT_ID(N'dbo.ufn_DayOfPeriod', 'FN') IS NOT NULL 2 BEGIN 3 DROP FUNCTION dbo.ufn_DayOfPeriod; 4 END 5 GO 6 7 --================================== 8 -- 功能: 獲得指定日期時間在當前旬的日索引 9 -- 說明: 從1開始計數,包括1、2、3、……、8、9、10、11 10 -- 作者: XXX 11 -- 創建: yyyy-MM-dd 12 -- 修改: yyyy-MM-dd XXX 修改內容描述 13 -- 調用: SET @intPeriods = dbo.ufn_DayOfPeriod('2008-01-14') 14 --================================== 15 CREATE FUNCTION [dbo].[ufn_DayOfPeriod] 16 ( 17 @dtmDate DATETIME -- 指定的日期時間 18 ) RETURNS TINYINT 19 --$Encode$-- 20 AS 21 BEGIN 22 RETURN DAY(@dtmDate) - (dbo.ufn_PeriodOfMonth(@dtmDate) - 1) * 10; 23 END 24 GOView Code
提供旬基準日期和整數相互轉換的功能函數,T-SQL代碼如下:
1 IF OBJECT_ID(N'dbo.ufn_Periods', 'FN') IS NOT NULL 2 BEGIN 3 DROP FUNCTION dbo.ufn_Periods; 4 END 5 GO 6 7 --================================== 8 -- 功能: 獲得指定日期時間基於基準日期的總旬數(一個整數值) 9 -- 說明: 如果指定的日期時間為NULL或者小於基準日期“1900-01-01”時,則其值預設基準日期; 10 -- 結果值為非負整數,從0開始計數。 11 -- 作者: XXX 12 -- 創建: yyyy-MM-dd 13 -- 修改: yyyy-MM-dd XXX 修改內容描述 14 -- 調用: SET @intPeriods = dbo.ufn_Periods('2008-01-14') 15 --================================== 16 CREATE FUNCTION [dbo].[ufn_Periods] 17 ( 18 @dtmDate DATETIME -- 指定的日期時間 19 ) RETURNS INT 20 --$Encode$-- 21 AS 22 BEGIN 23 SET @dtmDate = dbo.ufn_GetValidDate(@dtmDate); 24 25 -- 旬偏移索引ID,0:上旬,1:中旬,2:下旬 26 DECLARE @tintPeriodOffsetIndexID AS INT; 27 SET @tintPeriodOffsetIndexID = dbo.ufn_PeriodOfMonth(@dtmDate); 28 29 -- datepart參數也可以為mm或m 30 RETURN DATEDIFF(MONTH, '1900-01-01', @dtmDate) * 3 + @tintPeriodOffsetIndexID; 31 END 32 GO 33 34 IF OBJECT_ID(N'dbo.ufn_Periods2Date', 'FN') IS NOT NULL 35 BEGIN 36 DROP FUNCTION dbo.ufn_Periods2Date; 37 END 38 GO 39 40 --================================== 41 -- 功能: 獲得一個整數值基於基準日期對應的旬基準日期 42 -- 說明: 如果指定的整數值為NULL或為負整數時,則其值預設為0; 43 -- 如果指定的整數值大於“9999-12-31”對應的整數值時,則其值預設設置為“9999-12-31”對應的整數值; 44 -- 結果值為從基準日期開始計數的日期; 45 -- 旬基準日期是指一個月份中第1天、第11天和第21天對應的日期,比如'2016-02'月份的3個旬基準日期分別為'2016-02-01','2016-02-11','2016-02-21'。 46 -- 作者: XXX 47 -- 創建: yyyy-MM-dd 48 -- 修改: yyyy-MM-dd XXX 修改內容描述 49 -- 調用: SET @dtmDate = dbo.ufn_Periods2Date(2705) --'1975-02-21' 50 --================================== 51 Create FUNCTION dbo.ufn_Periods2Date 52 ( 53 @intPeriods INT 54 ) RETURNS DATETIME 55 AS 56 BEGIN 57 SET @intPeriods = dbo.ufn_GetValidDateNum(@intPeriods); 58 59 DECLARE @intMaxPeriods AS INT; 60 SET @intMaxPeriods = dbo.ufn_Periods('9999-12-31'); 61 62 IF @intPeriods >= @intMaxPeriods 63 BEGIN 64 SET @intPeriods = @intMaxPeriods; 65 END 66 67 -- datepart參數也可以為mm或m 68 -- 以下註釋的也可以,不過更接近相對日期+偏移數得到旬基準日期。 69 --RETURN DATEADD(MONTH, @intPeriods / 3, '1900-01-01') + (@intPeriods - @intPeriods / 3 * 3) * 10; 70 RETURN DATEADD(DAY, (@intPeriods - @intPeriods / 3 * 3) * 10, DATEADD(MONTH, @intPeriods / 3, '1900-01-01')); 71 END 72 GOView Code
測試以上4個函數效果的T-SQL代碼如下:
1 DECLARE @dtmDate AS DATETIME; 2 SET @dtmDate = '2016-01-08'; 3 4 SELECT dbo.ufn_PeriodOfMonth(@dtmDate) AS 'Period IndexID Of Current Month(1:上旬,2:中旬,3:下旬)' 5 ,dbo.ufn_DayOfPeriod(@dtmDate) AS 'Day IndexID Of Current Period(從1開始結束,包括1、2、3、……、10、11)'; 6 7 SELECT dbo.ufn_Periods('1900-02-01') AS 'The Total Of Periods Base-on BaseDate"1900-01-01" ' 8 ,dbo.ufn_Periods2Date(1) AS 'Period Basedate Mapping 100' 9 GOView Code
執行後的查詢結果如下圖:
SQL Server月有關時間粒度 在旬時間粒度小節中,我們引入了旬基準日期的概念,針對月基準日期的定義就是每月的第一天代表的日期時間值,比如”2016-01-08“所在的月基準日期就是”2016-01-01“。我們也提供月基準日期和整數相互轉換的功能函數。指定日期的月份在當前季度中的月索引,從1開始計數,包括1、2、3。SQL Server提供了month(@dtmDateTime)或datepart(month, @dtmDateTime)獲取指定日期所在月份(當前年的份索引,從1開始計數,包括1,、2、3、……、10、11、12)。 提供獲得指定日期的月份在當前季度的月索引,T_SQL代碼如下:
1 IF OBJECT_ID(N'dbo.ufn_MonthOfQuarter', N'FN') IS NOT NULL 2 BEGIN 3 DROP FUNCTION dbo.ufn_MonthOfQuarter; 4 END 5 GO 6 7 --================================== 8 -- 功能: 獲得一個日期時間的月份在當前季度的月索引 9 -- 說明: 如果指定的整數值為NULL時,則其值預設設置為基準日期'1900-01-01'; 10 -- 結果值從1開始計數,包括1、2、3。 11 -- 作者: XXX 12 -- 創建: yyyy-MM-dd 13 -- 修改: yyyy-MM-dd XXX 修改內容描述 14 -- 調用: SET @dtmDate = dbo.ufn_MonthOfQuarter(2008-01-01); 15 --================================== 16 CREATE FUNCTION dbo.ufn_MonthOfQuarter 17 ( 18 @dtmDate DATETIME -- 指定的日期時間 19 ) RETURNS TINYINT 20 AS 21 BEGIN 22 SET @dtmDate = ISNULL(@dtmDate, '1900-01-01'); 23 DECLARE @tintMonthOfQuarter AS TINYINT; 24 SET @tintMonthOfQuarter = 0; 25 26 DECLARE @tintMonthOfYear AS TINYINT; 27 SET @tintMonthOfYear = MONTH(@dtmDate); 28 29 SET @tintMonthOfQuarter = @tintMonthOfYear - @tintMonthOfYear / 3 * 3; 30 31 IF @tintMonthOfQuarter = 0 32 BEGIN 33 SET @tintMonthOfQuarter = 3; 34 END 35 36 RETURN @tintMonthOfQuarter; 37 END 38 GO 39View Code
提供月基準日期和整數相互轉換的功能函數,T-SQL代碼入下:
1 IF OBJECT_ID(N'dbo.ufn_Months', 'FN') IS NOT NULL 2 BEGIN 3 DROP FUNCTION dbo.ufn_Months; 4 END 5 GO 6 7 --================================== 8 -- 功能: 獲得指定日期時間基於基準日期的總月數(一個整數值) 9 -- 說明: 如果指定的日期時間為NULL或者小於基準日期“1900-01-01”時,則其值預設基準日期 10 -- 結果值為非負整數,從0開始計數。 11 -- 作者: XXX 12 -- 創建: yyyy-MM-dd 13 -- 修改: yyyy-MM-dd XXX 修改內容描述 14 -- 調用: SET @intMonths = dbo.ufn_Months('2008-01-14') 15 --================================== 16 CREATE FUNCTION dbo.ufn_Months 17 ( 18 @dtmDate DATETIME 19 ) RETURNS INT 20 AS 21 BEGIN 22 IF @dtmDate IS NULL OR @dtmDate < '1900-01-01' 23 BEGIN 24 SET @dtmDate = '1900-01-01'; 25 END 26 27 -- datepart參數也可以為mm或m 28 RETURN DATEDIFF(MONTH, '1900-01-01', @dtmDate); 29 END 30 GO 31 32 IF OBJECT_ID(N'dbo.ufn_Months2Date', 'FN') IS NOT NULL 33 BEGIN 34 DROP FUNCTION dbo.ufn_Months2Date; 35 END 36 GO 37 38 --================================== 39 -- 功能: 獲得一個整數值基於基準日期對應的月基準日期 40 -- 說明: 如果指定的整數值為NULL或為負整數時,則其值預設為0; 41 -- 如果指定的整數值大於“9999-12-31”對應的整數值時,則其值預設設置為“9999-12-31”對應的整數值; 42 -- 結果值為從基準日期開始計數的日期; 43 -- 月基準日期是指一個月份中第1天對應的日期,比如'2016-02'月份的月旬基準日期為'2016-02-01'。 44 -- 作者: XXX 45 -- 創建: yyyy-MM-dd 46 -- 修改: yyyy-MM-dd XXX 修改內容描述 47 -- 調用: SET @dtmDate = dbo.ufn_Months2Date(1296) --'2008-01-01' 48 --================================== 49 CREATE FUNCTION dbo.ufn_Months2Date 50 ( 51 @intMonths INT 52 ) RETURNS DATETIME 53 AS 54 BEGIN 55 IF @intMonths IS NULL OR @intMonths < 0 56 BEGIN 57 SET @intMonths = 0; 58 END 59 60 DECLARE @intMaxMonths AS INT; 61 SET @intMaxMonths = dbo.ufn_Months('9999-12-31'); 62 63 IF @intMonths >= @intMaxMonths 64 BEGIN 65 SET @intMonths = @intMaxMonths; 66 END 67 68 -- datepart參數也可以為mm或m 69 RETURN DATEADD(MONTH, @intMonths, '1900-01-01'); 70 END 71 GOView Code
測試有關月時間粒度的函數效果的T-SQL代碼如下:
1 DECLARE @dtmDate AS DATETIME; 2 SET @dtmDate = '2016-01-08'; 3 4 SELECT dbo.ufn_MonthOfQuarter(@dtmDate) AS 'Month IndexID Of Current Quarter(1:第1個月,2:第2個月,3:第3個月)' 5 ,MONTH(@dtmDate) AS 'Month IndexID Of Current Year', DATEPART(MONTH, @dtmDate) AS 'Month IndexID Of Current Year(從1開始結束,包括1、2、3、……、10、12))'; 6 7 SELECT dbo.ufn_Months(@dtmDate) AS 'The Total Of Months Base-on BaseDate"1900-01-01"' 8 ,dbo.ufn_Months2Date(2) AS 'Month Basedate Mapping 2'; 9 GOView Code
執行後的查詢結果如下圖: SQL Server函數重構 在旬和月時間粒度已經提供的功能函數,我們會針對指定的日期時間和整數參數做進行相應的條件處理,發現了很多的重覆T-SQL代碼,為消除相似功能的重覆代碼,我將其封裝在以下兩個功能函數ufn_GetVlidDate和ufn_GetValidDateNum,分別提供對指定的日期時間和指定的日期數的有效性處理。 提供以上功能函數的重構,T-SQL代碼如下:
1 IF OBJECT_ID(N'dbo.ufn_GetValidDate', 'FN') IS NOT NULL 2 BEGIN 3 DROP FUNCTION dbo.ufn_GetValidDate; 4 END 5 GO 6 7 --================================== 8 -- 功能: 獲取有效日期 9 -- 說明: 指定的日期如果為NULL或者小於基準日期'1900-01-01'則預設設置為基準日期'1900-00-01' 10 -- 作者: XXX 11 -- 創建: yyyy-MM-dd 12 -- 修改: yyyy-MM-dd XXX 修改內容描述 13 -- 調用: SET @dtmDate = dbo.ufn_GetValidDate('2008-01-14') 14 --================================== 15 CREATE FUNCTION dbo.ufn_GetValidDate 16 ( 17 @dtmDate DATETIME -- 指定的日期數 18 ) RETURNS DATETIME 19 --$Encode$-- 20 BEGIN 21 IF @dtmDate IS NULL OR @dtmDate < '1900-01-01' 22 BEGIN 23 RETURN '1900-01-01'; 24 END 25 26 RETURN @dtmDate; 27 END 28 GO 29 30 IF OBJECT_ID(N'dbo.ufn_GetValidDateNum', 'FN') IS NOT NULL 31 BEGIN 32 DROP FUNCTION dbo.ufn_GetValidDateNum; 33 END 34 GO 35 36 --================================== 37 -- 功能: 獲取有效日期數 38 -- 說明: 指定的日期數如果為NULL或負數,則預設設置為0 39 -- 作者: XXX 40 -- 創建: yyyy-MM-dd 41 -- 修改: yyyy-MM-dd XXX 修改內容描述 42 -- 調用: SET @@intDateNum = dbo.ufn_GetValidDateNum(-1) 43 --================================== 44 CREATE FUNCTION dbo.ufn_GetValidDateNum 45 ( 46 @intDateNum INT -- 指定的日期數 47 ) RETURNS INT 48 --$Encode$-- 49 BEGIN 50 IF @intDateNum IS NULL OR @intDateNum < 0 51 BEGIN 52 RETURN 0; 53 END 54 55 RETURN @intDateNum; 56 END 57 GOView Code
測試以上功能函數的T-SQL代碼如下:
1 SELECT dbo.ufn_GetValidDate(NULL) AS 'NULL Default BaseDate"1900-01-01"', dbo.ufn_GetValidDate('1899-12-31') AS