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

SQL Server 輕鬆實現日報與月報統計查詢技巧

     編輯:關於SqlServer

前言

在日常資料庫開發與維護中,依據日期區間統計業務數據(如每日訂單量、每月銷售額)是極為常見的需求。本文將通過具體範例,示範如何在 SQL Server 中高效編寫日報與月報查詢語句,並對比 Oracle 的寫法差異,幫助開發者快速掌握核心技巧。

一、日報查詢:精確鎖定單日數據

日報的關鍵在於「精確截取某一天的時間範圍」。許多初學者習慣使用 BETWEEN,但這在包含時間成分的 DATETIME 欄位上容易產生邊界問題(例如會漏掉 '2009-01-01 23:59:59' 之後的數據)。最佳實踐是採用 「大於等於起始日期,且小於隔天日期」 的半開半閉區間寫法。

SQL Server 寫法

-- 查詢 2009-01-01 當天,客戶 A1、A2、A3 的訂單總數量
SELECT 
    Cust_Name,
    CONVERT(CHAR(10), Order_Date, 120) AS Order_Date, -- 格式化為 YYYY-MM-DD
    SUM(Qty) AS Qty
FROM Orders_Big
WHERE 1=1
    AND Cust_Name IN ('A1', 'A2', 'A3')
    AND Order_Date >= '2009-01-01'      -- 包含當天 00:00:00
    AND Order_Date < '2009-01-02'         -- 排除隔天 00:00:00
GROUP BY 
    Cust_Name, 
    CONVERT(CHAR(10), Order_Date, 120)
ORDER BY 2, 1;

核心解析:

  • CONVERT(CHAR(10), Order_Date, 120):使用樣式 120 (ODBC 標準 yyyy-mm-dd) 截取日期部分,去除時間,便於分組。
  • 篩選條件 Order_Date >= '2009-01-01' AND Order_Date < '2009-01-02':這是處理日期範圍最安全、效能最好(可用索引)的方式。

Oracle 寫法對比

SELECT 
    Cust_Name,
    TO_CHAR(Order_Date, 'YYYY-MM-DD') AS Order_Date, -- 方法一:轉字串
    -- TRUNC(Order_Date) AS Order_Date,             -- 方法二:截斷時間 (推薦,可用索引)
    SUM(Qty) AS Qty
FROM Orders_Big
WHERE 1=1
    AND Cust_Name IN ('A1', 'A2', 'A3')
    AND Order_Date >= DATE '2009-01-01'
    AND Order_Date < DATE '2009-01-02'
GROUP BY 
    Cust_Name, 
    TO_CHAR(Order_Date, 'YYYY-MM-DD') -- 或 TRUNC(Order_Date)
ORDER BY 2, 1;

Oracle 中 TRUNC(Order_Date) 直接截斷時間部分,語意更清晰,且若在 Order_Date 上有函數索引,效能極佳。

二、月報查詢:按年月彙總

月報邏輯同理,只需將日期截取到「年-月」粒度,篩選條件鎖定整個月份區間。

SQL Server 寫法

-- 查詢 2009 年 1 月份報表
SELECT 
    Cust_Name,
    CONVERT(CHAR(7), Order_Date, 120) AS Order_YrMs,       -- 取得 '2009-01'
    CAST(CONVERT(CHAR(7), Order_Date, 120) + '-01' AS DATETIME) AS Order_Date, -- 補齊為月首日期
    SUM(Qty) AS Qty
FROM Orders_Big
WHERE 1=1
    AND Cust_Name IN ('A1', 'A2', 'A3')
    AND Order_Date >= '2009-01-01'
    AND Order_Date < '2009-02-01'         -- 關鍵:小於 2 月 1 號,涵蓋 1 月所有天數
GROUP BY 
    Cust_Name, 
    CONVERT(CHAR(7), Order_Date, 120)
ORDER BY 2, 1;

Oracle 寫法對比

SELECT 
    Cust_Name,
    TO_CHAR(Order_Date, 'YYYY-MM') AS Order_YrMs,      -- 方法一
    -- TRUNC(Order_Date, 'MM') AS Order_Date,           -- 方法二:截斷到月首 (推薦)
    SUM(Qty) AS Qty
FROM Orders_Big
WHERE 1=1
    AND Cust_Name IN ('A1', 'A2', 'A3')
    AND Order_Date >= DATE '2009-01-01'
    AND Order_Date < DATE '2009-02-01'
GROUP BY 
    Cust_Name, 
    TO_CHAR(Order_Date, 'YYYY-MM') -- 或 TRUNC(Order_Date, 'MM')
ORDER BY 2, 1;

三、效能優化與最佳實踐建議

  1. 索引策略:在 Order_Date 與 Cust_Name 上建立複合索引 (Cust_Name, Order_Date),可顯著加速篩選與分組。
  2. 避免對欄位做函數運算:WHERE 條件中盡量不要寫 WHERE CONVERT(CHAR(10), Order_Date, 120) = '2009-01-01',這會導致索引失效,改用區間查詢。
  3. 參數化查詢:實際應用中請使用參數(如 @StartDate, @EndDate)而非硬編碼日期,利於計畫快取重用,防止 SQL 注入。
  4. 大數據量分頁:若報表數據極大,建議先彙總到臨時表或使用分頁技術(OFFSET ... FETCH)分批返回前端。

總結

掌握「半開半閉區間」查詢日期範圍,搭配 CONVERT 或 FORMAT (SQL Server 2012+) 進行日期格式化分組,即可輕鬆實現高效、準確的日報與月報功能。這套邏輯通用於各主流關聯式資料庫,只需調整日期函數語法即可無縫遷移。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved