Implementation
The query is quite well written for what it does. I just have a few minor nitpicks about its implementation.
The FROM
, GROUP BY
, and ORDER BY
clauses are all subsidiary to the SELECT
clause. Therefore, I would indent them by one level. (Indenting your INNER JOIN
clauses so that they are part of the FROM
clause was good.)
You're getting the disadvantages of the comma-first convention without reaping the benefits. The advantage of putting commas first is that it makes it foolproof to add or remove columns in the SELECT
: you should be able to delete an entire line of text without having to worry about fixing commas on neighbouring lines. However, to take advantage of that property, you should put the first column on the same line as the SELECT
keyword:
SELECT Users.Id as [User Link]
, Users.DisplayName
, COUNT (Badges.Id) AS Number_of_Tag_Badges
FROM …
Remove the space before the parenthesis in the COUNT (…)
call.
The joins would be better if the tables were listed linearly:
$$ \fbox{Users} \overset{\texttt{UserId}}{\longleftrightarrow}
\fbox{Badges} \overset{\texttt{Name}}{\longleftrightarrow} \fbox{Tags}$$
Since the displayed results are user-centric, I would suggest listing the tables as Users
, Badges
, Tags
rather than any other order.
Concept
It would be handy if you added a rank column.
The query doesn't distinguish between gold, silver, and bronze badges. You should be able to report the breakdown. The convention used by the International Olympic Committee is to sort by the gold medal count first, rather than by the total. Perhaps you should do the same.
WITH EarnedTagBadges AS (
SELECT Users.DisplayName
, Badges.UserId
, Badges.Name
, RANK() OVER (PARTITION BY Users.Id, Badges.Name ORDER BY Date) AS Level
FROM Users
INNER JOIN Badges ON Users.Id = Badges.UserId
INNER JOIN Tags ON Badges.Name = Tags.TagName
), UserTagBadges AS (
SELECT UserId
, DisplayName
, COUNT(CASE WHEN Level = 3 THEN 1 END) AS Gold
, COUNT(CASE WHEN Level = 2 THEN 1 END) AS Silver
, COUNT(CASE WHEN Level = 1 THEN 1 END) AS Bronze
, COUNT(Level) AS Total
FROM EarnedTagBadges
GROUP BY UserId, DisplayName
)
SELECT RANK() OVER (ORDER BY Gold DESC, Silver DESC, Bronze DESC) AS Rank
, UserId AS [User Link]
, DisplayName
, Gold
, Silver
, Bronze
, Total
FROM UserTagBadges
ORDER BY Gold DESC, Silver DESC, Bronze DESC;
Users.Id
as[User Link]
andDisplayName
? \$\endgroup\$