问题
I am developing a training management web-based system which will show the management the training record for each division. My database design is like following:
Employee Table: Username, Name, Job, DivisionID
Division Table: DivisionID, DivisionName
Quiz Table: QuizID, Title, Description
UserQuiz Table: UserQuizID, Score, DateTimeComplete, QuizID, Username
NOTE: The first attribute in each table is the primary key.
The SQL Query that I am using for this task is:
SELECT COUNT(DISTINCT dbo.UserQuiz.QuizID) AS [Total Number of Quizzes],
dbo.Divisions.DivisionName,
DATENAME(Month, dbo.UserQuiz.DateTimeComplete) AS Month
FROM dbo.UserQuiz
INNER JOIN dbo.Quiz
ON dbo.UserQuiz.QuizID = dbo.Quiz.QuizID
INNER JOIN dbo.employee
ON dbo.UserQuiz.Username = dbo.employee.Username
RIGHT OUTER JOIN dbo.Divisions
ON dbo.employee.DivisionCode = dbo.Divisions.SapCode
GROUP BY dbo.Divisions.DivisionName,
DATENAME(Month, dbo.UserQuiz.DateTimeComplete)
This query will show me the total number of taken quizzes by each division based on month. What I want now is showing these results for the last three months. Also, I want to show all the divisions even if there is a division which does not take any quiz. This means I want to show the division with zero number of taken quizzes.
回答1:
For showing ALL Divisions, that will need to be first in the list, then LEFT JOINed to the count results. You'll need to COALESCE() the value so if null, will return the zero instead. As for the last 3 months, you'll just need to add a WHERE clause for the date range.
Edit... per comment. I've taken it one step further and for each division, I've created it as a Cross-Tab to show the division with 3 columns showing the counts of each respective month in a single row... So, the resulting column names would be the same, but would reflect the actual month data content... Actually adjusted the WHERE clause going back only 2 months... 2 months back plus current equals 3 months total.
select
d.DivisionName,
SUM( case when PreQuery.ByMonth = DATENAME(Month, DateAdd( month, -2, GetDate())
then PreQuery.DistinctQuizes else 0 end ) as TwoMonthsAgoCount,
SUM( case when PreQuery.ByMonth = DATENAME(Month, DateAdd( month, -1, GetDate())
then PreQuery.DistinctQuizes else 0 end ) as OneMonthAgoCount,
SUM( case when PreQuery.ByMonth = DATENAME(Month, GetDate())
then PreQuery.DistinctQuizes else 0 end ) as CurrentMonthCount
from
Divisions d
left join
( select count( distinct UQ.QuizID ) DistinctQuizes,
DATENAME(Month, UQ.DateTimeComplete) ByMonth,
d2.DivisionName
from
UserQuiz UQ
JOIN Quiz Q on UQ.QuizID = Q.QuizID
JOIN Employee E on UQ.UserName = E.UserName
JOIN Divisions D2 on E.DivisionCode = D2.SapCode
where
UQ.DateTimeComplete between
DateAdd( month, -2, GetDate()) and GetDate()
group by
d2.DivisionName,
DATENAME(Month, UQ.DateTimeComplete)
) PreQuery
ON d.DivisionName = PreQuery.DivisionName
GROUP BY
d.DivisionName
By using "GetDate()", this returns whatever the current date is on the computer. This would be the ENDING date. The first date would be basic date arithmetic... Use the DateAdd function, add an interval based on months of -2 (negative to go BACKWARDS), based on whatever the current date is.
来源:https://stackoverflow.com/questions/8462792/how-to-show-the-results-for-the-last-three-months