也许以下解决方案很复杂,但如果您有索引,它将为您提供更好的性能(这意味着 Index Seek)。这些示例基于AdventureWorks2008R2数据库:
SET NOCOUNT ON;
GO
DECLARE @StartDate DATETIME,@EndDate DATETIME;
PRINT 'Test #1: By YEAR';
DECLARE @Year SMALLINT;
SET @Year=2005;
SET @StartDate=CONVERT(CHAR(4),@Year)+'0101';
SET @EndDate=DATEADD(YEAR,DATEDIFF(YEAR,0,@StartDate)+1,0)
SELECT @StartDate AS StartDate,@EndDate AS EndDate
SELECT h.OrderDate,h.SalesOrderID
FROM Sales.SalesOrderHeader h
WHERE h.OrderDate>=@StartDate AND h.OrderDate<@EndDate;
PRINT 'Test #2: By MONTH';
DECLARE @Month TINYINT,@FromYear SMALLINT,@ToYear SMALLINT;
SET @Month=7;
SELECT @FromYear=YEAR(MIN(h.OrderDate)),@ToYear=YEAR(MAX(h.OrderDate))
FROM Sales.SalesOrderHeader h
SELECT @FromYear AS FromYear,@ToYear AS ToYear;
SET @StartDate=CONVERT(CHAR(4),@Year)+'0101';
SET @EndDate=DATEADD(YEAR,DATEDIFF(YEAR,0,@StartDate)+1,0);
WITH N10(Num)
AS
(
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL
SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10
)
SELECT y.*,h.OrderDate,h.SalesOrderID
FROM
(
SELECT x.StartDate,DATEADD(MONTH,DATEDIFF(MONTH,0,x.StartDate)+1,0) AS EndDate
FROM
(
SELECT CONVERT(DATETIME,CONVERT(CHAR(4),@FromYear-1+n.Num)+RIGHT('00'+CONVERT(VARCHAR(2),@Month),2)+'01') AS StartDate
FROM N10 n
WHERE n.Num<=(@ToYear+1-@FromYear)
) x
) y INNER JOIN Sales.SalesOrderHeader h ON h.OrderDate>=y.StartDate AND h.OrderDate<y.EndDate
结果:
Test #1: By YEAR
StartDate EndDate
----------------------- -----------------------
2005-01-01 00:00:00.000 2006-01-01 00:00:00.000
OrderDate SalesOrderID
----------------------- ------------
2005-07-01 00:00:00.000 43659
...
2005-12-31 00:00:00.000 45037
Test #2: By MONTH
FromYear ToYear
-------- ------
2005 2008
StartDate EndDate OrderDate SalesOrderID
--------- ----------------------- ----------------------- ------------
20050701 2005-08-01 00:00:00.000 2005-07-01 00:00:00.000 43659
...
20080701 2008-08-01 00:00:00.000 2008-07-01 00:00:00.000 74159
执行计划: