问题
Here is my original query:
SELECT
CAST(IndexedDate as varchar),
COUNT(*) AS Logins
FROM
Table
WHERE
EventType = 'Login'
AND IndexedDate > DATEADD(mm, -1, GETDATE())
GROUP BY
IndexedDate
ORDER BY
IndexedDate DESC
This would leave gaps, for example:
2016-09-13 41 2016-09-12 31 2016-09-09 15 2016-09-08 36
Based on this question, I tried the following and still received the gaps but on top of that the results were wrong (the numbers were MUCH higher):
SELECT
CAST(IndexedDate as varchar),
SUM(Case When COUNT(*) Is Null Then 0 Else COUNT(*) End) AS Logins
FROM
...
How can I get my results to look like this?
2016-09-13 41 2016-09-12 31 2016-09-11 0 2016-09-10 0 2016-09-09 15 2016-09-08 36
I've checked a few other questions but they all involve joins or other factors not in my scenario.
UPDATE
Based on comments, I've attempted an OUTER JOIN. This iteration finally ran successfully, but the results were a bit backwards...
SELECT
CAST(a.IndexedDate as varchar) as dt,
COUNT(*) AS Logins
FROM
(
SELECT *
FROM Table
WHERE IndexedDate > DATEADD(mm, -1, GETDATE())
AND EventType = 'Login'
) a
FULL OUTER JOIN (
SELECT DISTINCT(IndexedDate)
FROM Table
WHERE IndexedDate > DATEADD(mm, -1, GETDATE())
) b
ON
a.IndexedDate = b.IndexedDate
GROUP BY
b.IndexedDate
ORDER BY
b.IndexedDate DESC
Results:
2016-09-13 41 2016-09-12 31 (null) 1 (null) 1 2016-09-09 15 2016-09-08 36
I verified that aggregate b includes the missing dates.
回答1:
So I flipped the aggregates from the edit to my original post and now it's working:
Query
SELECT
CAST(a.IndexedDate as varchar) as dt,
COUNT(EventType) AS Logins
FROM
(
SELECT DISTINCT(IndexedDate)
FROM Table
WHERE IndexedDate > DATEADD(mm, -1, GETDATE())
) a
FULL OUTER JOIN (
SELECT *
FROM Table
WHERE IndexedDate > DATEADD(mm, -1, GETDATE())
AND EventType = 'Login'
) b
ON
a.IndexedDate = b.IndexedDate
GROUP BY
a.IndexedDate
ORDER BY
a.IndexedDate DESC
Results
2016-09-13 41 2016-09-12 31 2016-09-11 0 2016-09-10 0 2016-09-09 15 2016-09-08 36
Note that I had to replace COUNT(*) with COUNT(EventType) so it wouldn't count the date from the aggregate which was resulting in a 1.
回答2:
This works (in SQL Server)
declare @mindt date = (select min(IndexedDate ) from p);
declare @dtrange int = DATEDIFF(day,@mindt,(select max(IndexedDate ) from p));
with MyCte AS
(select MyCounter = 0
UNION ALL
SELECT MyCounter + 1
FROM MyCte
where MyCounter < @dtrange)
select coalesce(IndexedDate , dateadd(d, mycounter, @mindt)) IndexedDate
, count(IndexedDate)
from MyCte
left join p
on dateadd(d,mycounter,@mindt) = p.IndexedDate
group by coalesce(IndexedDate , dateadd(d, mycounter, @mindt))
option (maxrecursion 0);
We basically need two main figures, the starting date and the date range.
The we build a quick counter for the number of days in the date range.
Then we select each slot in the date range and assign a date and a value, if there are none we create a date with DateAdd and assign 0 as the value.
Here is a functional example
来源:https://stackoverflow.com/questions/39532916/return-0-in-group-by-when-count-is-null