首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 經典自定義函數集錦:月天數、周一日期、季度邊界、季度天數

     編輯:關於SqlServer

整理四個高頻日期計算標量函數,採用集合思維與日期邊界運算,無循環、無游標、高性能,可直接部署至生產庫供查詢、存儲過程、計算列調用。

1. 獲取指定日期所在月份天數

CREATE FUNCTION dbo.DaysInMonth (@dt DATETIME)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
    -- 核心邏輯:下月 1 號 - 1 天 = 本月最後一天
    RETURN DAY(DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, @dt) + 1, 0)));
END;
GO

-- 調用
SELECT dbo.DaysInMonth('2024-02-15'); -- 返回 29 (閏年)
SELECT dbo.DaysInMonth('2023-02-15'); -- 返回 28

原理解析:DATEDIFF(MONTH, 0, @dt) 獲取從 1900-01 到目標月的月份差 → +1 定位下月 → DATEADD(MONTH, ..., 0) 獲得下月 1 號 00:00 → DATEADD(DAY, -1, ...) 回退一天 → DAY() 取日期部分即天數。

2. 計算指定日期所在週的周一日期 (週起始日 = 周一)

-- 方法一:基準日期 1900-01-01 (周一)
SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19000101', GETDATE()), '19000101');

-- 方法二:基準 0 (1900-01-01 隱式轉換)
SELECT DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0);

-- 函數封裝
CREATE FUNCTION dbo.MondayOfWeek (@dt DATETIME)
RETURNS DATE
WITH SCHEMABINDING
AS
BEGIN
    RETURN DATEADD(WEEK, DATEDIFF(WEEK, 0, @dt), 0);
END;

注意:SQL Server 預設 @@DATEFIRST 決定週起始 (美式=7 周日,歐式=1 周一)。上述函數強制以周一為起始,跨語言環境穩定。

3. 獲取指定日期所在季度的第一天

SELECT DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0);
-- 返回 2024-10-01 00:00:00.000 (假設當前 Q4)

CREATE FUNCTION dbo.FirstDayOfQuarter (@dt DATETIME)
RETURNS DATE
WITH SCHEMABINDING
AS
BEGIN
    RETURN DATEADD(QUARTER, DATEDIFF(QUARTER, 0, @dt), 0);
END;

4. 計算指定日期所在季度的天數

CREATE FUNCTION dbo.DaysInQuarter (@dt DATETIME)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
    DECLARE @QuarterStart DATE = DATEADD(QUARTER, DATEDIFF(QUARTER, 0, @dt), 0);
    RETURN DATEDIFF(DAY, @QuarterStart, DATEADD(QUARTER, 1, @QuarterStart));
END;
GO

-- 等價內聯邏輯 (無需函數)
DECLARE @QuarterStart DATE = DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0);
SELECT DATEDIFF(DAY, @QuarterStart, DATEADD(QUARTER, 1, @QuarterStart)); -- 返回 92 (Q4)

性能與最佳實踐

iTVF 重寫示例 (高性能批量調用)

CREATE FUNCTION dbo.itvf_DaysInMonth (@dt DATETIME)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT DAY(DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, @dt) + 1, 0))) AS Days;
GO

-- 批量調用
SELECT t.OrderDate, d.Days
FROM Sales.SalesOrderHeader t
CROSS APPLY dbo.itvf_DaysInMonth(t.OrderDate) d;

掌握「邊界運算 + DATEDIFF/DATEADD 組合」核心模式,即可靈活構建任意粒度 (年/季/月/周/日) 的起始/結束/天數計算,無需查閱日曆表,性能極佳。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
函數類型特點建議
標量函數 (上述)易用、可 SCHEMABINDING、但大結果集逐行調用有函數開銷小結果集、計算列、WHERE 子句簡單值
內聯表值函數 (iTVF)優化器內聯展開、零開銷、可並行大批量查詢、JOIN、APPLY 場景首選
多語句表值函數 (mTVF)邏輯複雜、但有表變量開銷、不內聯極複雜邏輯無法單語句表達時