所以我在计算系统中用户的活动记录。我得到某个月和每年的每一天的活动计数器,就像下面的查询一样
SELECT CONVERT(date, VIS_DATETIME) AS DATETIME, COUNT(*) AS ACTIVITY
FROM ACTIVITY
WHERE DATEPART(year, VIS_DATETIME) = 2016 AND
DATEPART(month, VIS_DATETIME) = 3
GROUP BY CONVERT(date, VIS_DATETIME)
ORDER BY CONVERT(date, VIS_DATETIME)
问题是,如果,让我们说,3月28日没有任何活动,它甚至不会被列出。但是,对于我的图表API,我需要将其列出并使用0
作为计数器。
显然,接受建议!
答案 0 :(得分:4)
创建一个包含所有日期的表格。然后使用Activity表进行左连接。在日期上分组,并在Activity.id上执行COUNT
。左连接确保日期表中的所有日期都包含在结果集中,即使它们在join子句中不匹配。
答案 1 :(得分:4)
Declare @DayOfMonth TinyInt Set @DayOfMonth = 1
Declare @Month TinyInt Set @Month = 1
Declare @Year Integer Set @Year = 2016
Declare @startDate datetime
Declare @endDate datetime
-- ------------------------------------
Select @startDate = DateAdd(day, @DayOfMonth - 1,
DateAdd(month, @Month - 1,
DateAdd(Year, @Year-1900, 0)))
select @endDate = dateadd(month,1,@startDate)
;with dateRange as
(
select dt = dateadd(dd, 0, @startDate)
where dateadd(dd, 0, @startDate) < @endDate
union all
select dateadd(dd, 1, dt)
from dateRange
where dateadd(dd, 1, dt) < @endDate
)
select *
from dateRange
上面的查询给出了该月份的所有日期,您可以将其与您的聚合查询一起加入,以获得零计数的条目。
答案 2 :(得分:0)
这些如何运作?
alter table activity add column ActivityIsValid smallint default 1;
这样,新行作为有效活动进入,而不是无效。
然后安排SQL Server代理作业每天运行以下代码一次:
insert into activity(vis_datetime, ActivityIsValid)
values(cast(getdate() as date), 0);
然后您可以将查询运行为:
SELECT CONVERT(date, VIS_DATETIME) AS DATETIME,
SUM(CASE WHEN ActivityIsValid = 1 THEN 1 ELSE 0 END) AS ACTIVITY
FROM ACTIVITY
WHERE VIS_DATETIME >= '2016-03-01' AND
VIS_DATETIME < '2016-04-01
GROUP BY CONVERT(date, VIS_DATETIME)
ORDER BY CONVERT(date, VIS_DATETIME);
当然,这只会向前发展。您可以在历史数据中手动插入额外的行。
另请注意WHERE
子句的更改。通过直接日期比较,SQL引擎可以使用索引。
答案 3 :(得分:0)
类似于Arun's answer,这将创建一个可以连接的临时表,并节省在数据库中创建永久表的时间。
DECLARE @@startDate DATETIME = '2016-03-01';
DECLARE @@endDate DATETIME = '2016-03-31';
DECLARE @@tempCalendar TABLE (
[Id] INT IDENTITY(1,1) NOT NULL,
[Year] INT NOT NULL,
[Month] INT NOT NULL,
[Day] INT NOT NULL
);
DECLARE @@dateCount DATETIME = @@startDate;
WHILE (@@dateCount <= @@endDate)
BEGIN
INSERT INTO @@tempCalendar
VALUES (
DATEPART(YEAR, @@dateCount)
, DATEPART(MONTH, @@dateCount)
, DATEPART(DAY, @@dateCount)
);
SET @@dateCount = DATEADD(DAY, 1, @@dateCount);
END
SELECT c.[Year]
, c.[Month]
, c.[Day]
, COUNT(a.Id) AS ACTIVITY
FROM @@tempCalendar c
LEFT OUTER JOIN ACTIVITY a ON c.[Year] = DATEPART(YEAR, a.VIS_DATETIME)
AND c.[Month] = DATEPART(MONTH, a.VIS_DATETIME)
AND c.[Day] = DATEPART(DAY, a.VIS_DATETIME)
WHERE DATEPART(YEAR, a.VIS_DATETIME) = DATEPART(YEAR, @@startDate)
AND DATEPART(MONTH, a.VIS_DATETIME) = DATEPART(MONTH, @@startDate)
GROUP BY c.[Year], c.[Month], c.[Day]
ORDER BY c.[Year], c.[Month], c.[Day];