我觉得我之前已经看过这个问题了,但SO搜索和谷歌都没有帮助我...也许我只是不知道如何说出这个问题。我需要计算给定时间跨度内每天的事件数(在本例中为登录),以便我可以制作网站使用情况的图表。我到目前为止的查询是:
select
count(userid) as numlogins,
count(distinct userid) as numusers,
convert(varchar, entryts, 101) as date
from
usagelog
group by
convert(varchar, entryts, 101)
这完成了我需要的大部分工作(每个日期我得到一行作为包含登录总数和该日期唯一用户数的输出)。问题是如果没有人在给定日期登录,那么该日期的数据集中就不会有一行。我希望它添加行,表示这些日期的零登录。我可以想到两种方法来解决这个问题,而且我也不会非常优雅。
谷歌更好的搜索条件有哪些更好的解决方案或提示?感谢。
答案 0 :(得分:3)
坦率地说,我在构建最终输出时以编程方式执行此操作。你本质上是想从数据库中读取一些不存在的东西(没有数据的天数)。 SQL并不是真正意义上的那种东西。
如果你真的想这样做,那么“约会”表似乎是你最好的选择。为了使它更好一些,您可以使用即数据库的日期函数和派生表来动态生成它。
答案 1 :(得分:2)
我最近必须做同样的事情。这就是我在T-SQL中的做法( YMMV的速度,但我发现它在足够数百万行的事件数据中表现得足够高):
DECLARE @DaysTable TABLE ( [Year] INT, [Day] INT )
DECLARE @StartDate DATETIME
SET @StartDate = whatever
WHILE (@StartDate <= GETDATE())
BEGIN
INSERT INTO @DaysTable ( [Year], [Day] )
SELECT DATEPART(YEAR, @StartDate), DATEPART(DAYOFYEAR, @StartDate)
SELECT @StartDate = DATEADD(DAY, 1, @StartDate)
END
-- This gives me a table of all days since whenever
-- you could select @StartDate as the minimum date of your usage log)
SELECT days.Year, days.Day, events.NumEvents
FROM @DaysTable AS days
LEFT JOIN (
SELECT
COUNT(*) AS NumEvents
DATEPART(YEAR, LogDate) AS [Year],
DATEPART(DAYOFYEAR, LogDate) AS [Day]
FROM LogData
GROUP BY
DATEPART(YEAR, LogDate),
DATEPART(DAYOFYEAR, LogDate)
) AS events ON days.Year = events.Year AND days.Day = events.Day
答案 2 :(得分:1)
创建一个内存表(一个表变量),在其中插入日期范围,然后将登录表外部连接到它。按开始日期分组,然后您就可以执行汇总和计算。
答案 3 :(得分:1)
我通常使用的策略是与查询相反的UNION,通常是检索不存在的行的数据的查询。
如果我想获得一门课程的平均分,但是有些课程没有被任何学生带走,我需要UNION和那些没有被任何人带走的人在每个班级上显示一行:
SELECT AVG(mark), course FROM `marks`
UNION
SELECT NULL, course FROM courses WHERE course NOT IN
(SELECT course FROM marks)
您的查询会更复杂,但应遵循相同的原则。您可能确实需要第二个查询的日期表
答案 4 :(得分:1)
选项1 您可以创建临时表并使用范围插入日期,并使用usagelog执行左外连接 选项2 您可以在评估结果集时以编程方式插入缺少的日期以生成最终输出
答案 5 :(得分:0)
WITH q(n) AS
(
SELECT 0
UNION ALL
SELECT n + 1
FROM q
WHERE n < 99
),
qq(n) AS
(
SELECT 0
UNION ALL
SELECT n + 1
FROM q
WHERE n < 99
),
dates AS
(
SELECT q.n * 100 + qq.n AS ndate
FROM q, qq
)
SELECT COUNT(userid) as numlogins,
COUNT(DISTINCT userid) as numusers,
CAST('2000-01-01' + ndate AS DATETIME) as date
FROM dates
LEFT JOIN
usagelog
ON entryts >= CAST('2000-01-01' AS DATETIME) + ndate
AND entryts < CAST('2000-01-01' AS DATETIME) + ndate + 1
GROUP BY
ndate
这将最多选择动态构建的10,000
日期,这应该足够30
年。
SQL Server
每个100
的{{1}}递归限制,这就是内部查询每次最多返回CTE
行的原因。
如果您需要的时间超过100
,只需添加第三个10,000
CTE
并在qqq(n)
中与其交叉加入。