我有一个简单的查询,它对日期数据进行分组和排序:
SELECT COUNT(*) AS Events,
datepart(YYYY, call_date) AS YearPart,
datepart(MM, call_date) As MonthPart,
datename(YYYY, call_date) AS YearName,
dateName(MM, call_date) As MonthName
FROM rm_report
GROUP BY
datename(year, call_date),
datename(month, call_date),
datepart(year, call_date),
datepart(month, call_date)
ORDER BY
YearPart,
MonthPart;
问题是第一年的头两个月没有数据。因此,订购在第三个月开始,然后循环到第一个
EVENTS | YEARPART | YEARNAME | MONTHPART | MONTHNAME
3 2012 2012 3 March
6 2012 2012 4 April
6 2012 2012 5 May
6 2012 2012 6 June
6 2012 2012 7 July
6 2012 2012 8 August
6 2012 2012 9 September
6 2012 2012 10 October
6 2012 2012 11 November
6 2012 2012 12 December
6 2012 2013 1 January
6 2012 2013 2 February
如何确保如果没有事件,则分配0以便列表可以正确排序 - 这是MonthPart
列中的第一个条目是" 1"并且YearPart
列中的第一个条目是2012年?
我们正在使用MS SQL。
答案 0 :(得分:2)
使用一列MONTHPART创建临时表/ CTE,其中包含1-12的数字。使用此表加入您的结果并将NULLS替换为零。
示例:
CREATE TABLE #temp
(
[monthpart] INT
)
INSERT INTO #Temp (MONTHPART) Values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
--SELECT * FROM #Temp
SELECT [monthpart],
ISNULL([deptid], 0) AS Department,
ISNULL(SUM([salart]), 0) AS Salary
FROM [DeeTest].[dbo].[employeesalary]
RIGHT JOIN #temp
ON empid = monthpart
GROUP BY deptid,
monthpart
DROP TABLE #temp
答案 1 :(得分:2)
您需要先生成month
和year
的所有组合。然后在LEFT JOIN
上执行rm_report
:
WITH CteTally(N) AS(
SELECT N FROM(VALUES
(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)
)t(N)
),
CteDates(YearPart, MonthPart, YearName, MonthName) AS(
SELECT
DATEPART(YEAR, DATEADD(MONTH, t.N - 1, DATEADD(YEAR, a.Y - 1900, 0))),
DATEPART(MONTH, DATEADD(MONTH, t.N - 1, DATEADD(YEAR, a.Y - 1900, 0))),
DATENAME(YEAR, DATEADD(MONTH, t.N - 1, DATEADD(YEAR, a.Y - 1900, 0))),
DATENAME(MONTH, DATEADD(MONTH, t.N - 1, DATEADD(YEAR, a.Y - 1900, 0)))
FROM(
SELECT DISTINCT DATEPART(YEAR, call_date) AS Y
FROM rm_report
)a
CROSS JOIN CteTally t
)
SELECT
COUNT(r.call_date) AS Events,
d.YearPart,
d.MonthPart,
d.YearName,
d.MonthName
FROM CteDates d
LEFT JOIN rm_report r
ON d.YearPart = DATEPART(YEAR, r.call_date)
AND d.YearName= DATENAME(YEAR, r.call_date)
AND d.MonthPart = DATEPART(MONTH, r.call_date)
AND d.MonthName = DATENAME(MONTH, r.call_date)
GROUP BY
d.YearPart, d.YearName, d.MonthPart, d.MonthName
ORDER BY
d.YearName, d.MonthPart
答案 2 :(得分:2)
您可以按照Aaron Bertrand的建议创建一个日历表,并将查询写为:
--create Calendar table based on the max and min dates in table
DECLARE @Mincall_date DATETIME,@FromDate DATETIME, @ToDate DATETIME;
SET @Mincall_date = ( SELECT MIN (Call_date) FROM @rm_report);
SET @FromDate= DATEADD(yy, DATEDIFF(yy,0,@Mincall_date), 0)
SET @ToDate = ( SELECT MAX (Call_date) FROM @rm_report);
-- just the months in that period
DECLARE @Calendar TABLE( TheDate DATETIME,TheMonth INT, TheYear INT)
INSERT INTO @Calendar
SELECT TOP (DATEDIFF(MONTH, @FromDate, @ToDate)+1)
TheDate = DATEADD(MONTH, number, @FromDate),
TheMonth = MONTH(DATEADD(MONTH, number, @FromDate)),
TheYear = YEAR(DATEADD(MONTH, number, @FromDate))
FROM [master].dbo.spt_values
WHERE [type] = N'P' ORDER BY number;
--SELECT * FROM @Calendar
SELECT ISNULL(T.[Events],0) AS [Events],
ISNULL(T.YearPart,C.TheYear) AS YearPart,
ISNULL(T.MonthPart,C.TheMonth) AS MonthPart,
ISNULL(T.YearName,DATENAME(YYYY,C.TheDate)) AS YearName,
ISNULL(T.MonthName,DATENAME(MM,C.TheDate)) AS MonthName
FROM @Calendar C
LEFT JOIN
(
SELECT COUNT(*) AS Events,
datepart(YYYY, call_date) AS YearPart,
datepart(MM, call_date) As MonthPart,
datename(YYYY, call_date) AS YearName,
dateName(MM, call_date) As MonthName
FROM @rm_report
GROUP BY
datename(year, call_date),
datename(month, call_date),
datepart(year, call_date),
datepart(month, call_date)
) T
ON C.TheMonth=T.MonthPart AND C.TheYear = T.YearPart
ORDER BY
YearPart,
MonthPart;
答案 3 :(得分:0)
可以通过简单的选择
完成DECLARE @rm_report table
(
call_date datetime
)
INSERT @rm_report VALUES (GETDATE())
SELECT
(
SELECT COUNT(*)
FROM @rm_report
WHERE YEAR(call_date) = year.Value AND MONTH(call_date) = month.Value
) AS Events,
year.Value AS YearPart,
month.Value AS MonthPart,
year.Value AS YearName,
DATENAME(MM, DATEADD(MONTH, month.Value, '2000-12-01')) AS MonthName
FROM
(VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)) month(Value)
CROSS JOIN
(
SELECT DISTINCT YEAR(call_date) Value FROM @rm_report
) year