Don't convert dates to strings to strip time or day, use date arithmetic. Converting to strings is less efficient and also requires a scan of the entire table.
If you're going to convert to a fixed length string, don't use NVARCHAR
, use CHAR
. What Unicode characters are you going to need to support in a numeric date? Umlauts? Pound signs? Hieroglyphics?
Here is an example that uses a catalog view to generate 6 rows, then subtracts months away from the current date to group by the previous 6 months (and an index on Modification_Date
should be used, unlike your current approach). This is not entirely intuitive the first time you see it, but you can see my series on generating sets without loops (part 1 | part 2 | part 3).
;WITH x(m) AS
(
SELECT TOP 6 DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())
- (ROW_NUMBER() OVER (ORDER BY [object_id])), 0)
FROM sys.all_objects
ORDER BY [object_id]
)
SELECT [Month] = x.m, Quantity = COALESCE(COUNT(t.Artifact), 0)
FROM x
LEFT OUTER JOIN dbo.tablename AS t
ON t.Modification_Date >= x.m
AND t.Modification_Date < DATEADD(MONTH, 1, x.m)
GROUP BY x.m
ORDER BY x.m DESC;
Note that this will not include the current month. If you want to shift to include October -> March instead of September -> February, just change this line:
+ 1 - (ROW_NUMBER() OVER (ORDER BY [object_id])), 0)
And if formatting as YYYY-MM
is absolutely essential, you can do this:
;WITH y(m) AS
(
SELECT TOP 6 DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())
- (ROW_NUMBER() OVER (ORDER BY [object_id])), 0)
FROM sys.all_objects
ORDER BY [object_id]
),
x([Month], Quantity)
AS
(
SELECT [Month] = y.m, Quantity = COALESCE(COUNT(t.Artifact), 0)
FROM y
LEFT OUTER JOIN dbo.tablename AS t
ON t.Modification_Date >= y.m
AND t.Modification_Date < DATEADD(MONTH, 1, y.m)
GROUP BY y.m
)
SELECT [Month] = CONVERT(CHAR(7), [Month], 120), Quantity
FROM x
ORDER BY [Month] DESC;