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

T-SQL 實戰:依指定日期輸出所屬月份逐週日期區間

     編輯:Oracle 資料庫基礎

需求場景

給定任一日期,需輸出該日期所在月份的所有日期,並按「週次」分組顯示每週的起始日 (週日) 與結束日 (週六),自動處理跨月週邊界 (首週可能包含上月末尾、末週可能包含下月初首)。

完整 T-SQL 腳本 (SQL Server 語法)

DECLARE @i INT;                   -- 迴圈計數器
DECLARE @curWk INT;               -- 指定日期在該年的週數
DECLARE @fstWk INT;               -- 該月 1 號在該年的週數
DECLARE @fstDay NVARCHAR(10);     -- 該月第一天 (YYYY-MM-DD)
DECLARE @lstDay NVARCHAR(10);     -- 該月最後一天
DECLARE @tmpDay SMALLDATETIME;    -- 迴圈中當前週日日期
DECLARE @date SMALLDATETIME;      -- 輸入指定日期
DECLARE @tmpDay1 SMALLDATETIME;   -- 當週六日期

-- 測試輸入日期
SET @date = '2007-09-01';

-- 計算該月第一天字串
SELECT @fstDay = CONVERT(NVARCHAR(10), 
    CAST(CAST(YEAR(@date) AS NVARCHAR(4)) + '-' + 
         CAST(MONTH(@date) AS NVARCHAR(2)) + '-01' AS SMALLDATETIME), 120);

-- 取得該月第一天所屬週數
SET @fstWk = DATEPART(WK, @fstDay);

-- 計算該月最後一天
SET @lstDay = CONVERT(NVARCHAR(10), DATEADD(D, -1, DATEADD(M, 1, @fstDay)), 120);

-- ============================================================
-- 階段一:尋找本月第一個「完整週」的起始日 (週日)
-- 若 1 號非週日,則首週起始日為上個月的某個週日
-- ============================================================
SET @i = 0;
WHILE (@i < 8)
BEGIN
    SET @tmpDay = DATEADD(DD, @i, @fstDay);  -- 從 1 號往後推
    SET @curWk = DATEPART(WK, @tmpDay);
    IF @curWk > @fstWk  -- 週數變大,表示進入下一週 (找到週日)
    BEGIN
        BREAK;
    END
    SET @i = @i + 1;
END
-- 此時 @tmpDay 為本月第二週的週日 (或第一週週日若 1 號即為週日)

-- ============================================================
-- 階段二:逐週輸出日期區間
-- ============================================================
SET @i = 1;  -- 週次計數器

WHILE (@i < 7)  -- 一月最多 6 週
BEGIN
    IF @i = 1  -- 第一週特殊處理:從月首日到第一個週六
    BEGIN
        PRINT '第' + CAST(@i AS VARCHAR) + '週:' + @fstDay + '--------' + CONVERT(NVARCHAR(10), DATEADD(D, -1, @tmpDay), 120);
        SET @i = @i + 1;
    END

    -- 若當前週日尚未超過月尾,繼續處理
    IF DATEDIFF(D, @tmpDay, @lstDay) >= 0
    BEGIN
        SET @tmpDay1 = DATEADD(D, 6, @tmpDay);  -- 週六 = 週日 + 6

        -- 判斷週六是否超出月尾
        IF DATEDIFF(D, @lstDay, @tmpDay1) > 0  -- 週六 > 月尾
        BEGIN
            PRINT '第' + CAST(@i AS VARCHAR) + '週:' + CONVERT(NVARCHAR(10), @tmpDay, 120) + '--------' + CONVERT(NVARCHAR(10), @lstDay, 120);
        END
        ELSE
        BEGIN
            PRINT '第' + CAST(@i AS VARCHAR) + '週:' + CONVERT(NVARCHAR(10), @tmpDay, 120) + '--------' + CONVERT(NVARCHAR(10), @tmpDay1, 120);
        END
    END

    -- 移至下一週週日
    SET @tmpDay = DATEADD(D, 7, @tmpDay);

    -- 若下一週週日已超過月尾,結束迴圈
    IF DATEDIFF(D, @tmpDay, @lstDay) < 0
        BREAK;

    SET @i = @i + 1;
END

執行結果範例 (輸入 2007-09-01)

第1週:2007-09-01--------2007-09-01
第2週:2007-09-02--------2007-09-08
第3週:2007-09-09--------2007-09-15
第4週:2007-09-16--------2007-09-22
第5週:2007-09-23--------2007-09-29
第6週:2007-09-30--------2007-09-30

邏輯關鍵點解析

  1. DATEPART(WK, date):依 SQL Server 定義取得年度週數 (週日為週首)。
  2. 首週邊界處理:迴圈從 1 號向前推最多 7 天,找到週數變化點,即為第一個週日。
  3. 末週截斷:計算週六 (@tmpDay1),若超過月尾 (@lstDay),則以月尾為該週結束日。
  4. 迴圈終止條件:下一週週日超過月尾即跳出。

應用建議

  • 可封裝為預存程序 sp_GetMonthlyWeeks @InputDate 供報表呼叫。
  • 若需週一為週首,需調整 DATEFIRST 設定或改用 DATEPART(WEEKDAY, ...) 邏輯。
  • Oracle/PostgreSQL 等異構資料庫需改用對應日期函數 (TRUNC(date, 'IW') 等)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved