问题
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