对于 2005 年以上(对不起,我错过了 2000 年的要求):
DECLARE @Orders TABLE(OrderDate DATETIME, billed INT);
INSERT @Orders SELECT '20100104', 500
UNION SELECT '20100106', 700;
DECLARE
@year INT,
@end_month TINYINT;
SELECT
@year = 2010,
@end_month = 7;
WITH s(n) AS
(
SELECT TOP (@end_month) ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.objects ORDER BY [object_id]
),
m(s) AS
(
SELECT DATEADD(MONTH, n-1, DATEADD(YEAR, @year-1900, 0))
FROM s
)
SELECT
[Year] = @year,
[Month] = MONTH(m.s),
Billed = COALESCE(SUM(t.billed), 0)
FROM m
LEFT OUTER JOIN @Orders AS t
ON t.OrderDate >= m.s
AND t.OrderDate < DATEADD(MONTH, 1, m.s)
GROUP BY
MONTH(m.s)
ORDER BY [Year], [Month];
2000 年只是略有不同:
CREATE TABLE #Orders(OrderDate DATETIME, billed INT);
INSERT #Orders SELECT '20100104', 500
UNION SELECT '20100106', 700;
DECLARE
@year INT,
@end_month TINYINT;
SELECT
@year = 2010,
@end_month = 7;
SELECT
[year] = @year,
[month] = MONTH(m.s),
billed = COALESCE(SUM(t.billed), 0)
FROM
(
SELECT s = DATEADD(MONTH, n-1, DATEADD(YEAR, @year-1900, 0)) FROM
(
SELECT DISTINCT TOP 12 n = number
FROM master..spt_values
WHERE number BETWEEN 1 AND @end_month
ORDER BY number
)
AS s
) AS m
LEFT OUTER JOIN #Orders AS t
ON t.OrderDate >= m.s
AND t.OrderDate < DATEADD(MONTH, 1, m.s)
GROUP BY MONTH(m.s);
现在我承认我没有 2000 个实例可以方便地测试 - 这只是即兴发挥。