我有一个类似于以下内容的数据库架构:
| User | Event | Date
|--------|---------------|------
| 111 | Walked dog | 2009-10-1
| 222 | Walked dog | 2009-10-2
| 333 | Fed Fish | 2009-10-5
| 222 | Did Laundry | 2009-10-6
| 111 | Fed Fish | 2009-10-7
| 111 | Walked dog | 2009-10-18
| 222 | Walked dog | 2009-10-19
| 111 | Fed Fish | 2009-10-21
我想生成一个查询,该查询返回用户在一段时间内执行某些操作的最大次数。例如,给定5天的时间段,用户111遛狗的最大次数是多少?
最明显的解决方案是从某个零点开始,每天前进,总计5天的时间段,然后从所有5天的窗口中取出最大值。然而,这种方法似乎非常昂贵。
我很感激您的任何建议。
编辑1:
感谢您的评论/答案。回复:
- 我正在使用mySQL v5.0
- 每天可能有任意数量的事件(真正的每个时间段)
- @Paulo Santos:谢谢,但是就像评论指出的那样,我需要找到产生最多结果的窗口,窗口本身可以滑动。
- @Mark:这看起来像一个有趣的解决方案,虽然我记得读到mySQL不支持备份或跳过游标。
- @orbMan:这看起来很有希望。我还没有完全理解它,但今晚我会试一试。
- @mjv:另一个有前途的解决方案。也看起来很复杂,但我会再看一遍
再次感谢!
答案 0 :(得分:3)
对于特定的请求,我会执行以下操作:
SELECT User, Event, Count(*)
FROM Table
WHERE Date between @d1 and @d2
Group by User, Event
然后它将返回每个用户在指定的@d1
和@d2
)时间范围内执行每项任务的时间。
答案 1 :(得分:2)
select top 1 x.Date as StartDate, DATEADD(day, 5, x.Date) as EndDate, COUNT(*) as Count
from Event e
inner join Event x on 1=1
where e.Date between x.Date and DATEADD(day, 5, x.Date)
and e.Event = 'Walked dog'
group by x.Date, DATEADD(day, 5, x.Date)
order by Count desc
<强>输出:强>
StartDate EndDate Count
---------- ---------- -----------
2009-10-01 2009-10-06 2
答案 2 :(得分:1)
这是一种基于游标的替代算法。
从两个游标开始,开始和结束,两者都指向初始行,当前计数= 0,当前最大值= 0.
如果DATE_DIFF(end.date,begin.date)大于5,则将开始光标前进一行。如果旧行是“遛狗”,则从当前计数中减去一个。
如果DATE_DIFF(end.date,begin.date)不超过5,则将结束光标前进一行。如果新行是“遛狗”,Aadd将当前计数。如果当前计数大于当前最大值,则将当前最大值设置为当前计数。
继续,直到覆盖范围内的所有行。
答案 3 :(得分:1)
以下SQL代码以声明方式解决问题,而不是纯粹的程序/算法方式。根据具体情况,它可能更有效(与从SQL获取[已排序]数据然后运行某些算法相比,甚至与基于游标的服务器端解决方案相比。)
这个想法是在一个单独的表或CTE中获得每个用户每天[相关/已过滤]事件的计数。然后为每一天+用户,计算当天和接下来4天的事件数量,最后选择(每个用户)具有最大值的行。
SELECT User, Date, COUNT(*) AS EventCount
INTO tmpTableByUsrByDay
FROM myTable
-- WHERE Event = some_targeted_event --Optional condition(s)
GROUP BY User, Date, COUNT(*)
SELECT DISTINCT User, Date AS FirstDay,
MAX(FiveFaysEventCount) AS EventCountForThisAndNext4Days.
FROM (
SELECT T1.User, T1.Date, SUM(T2.EventCount) FiveDaysEventCount
FROM tmpTableByUsrByDay T1
JOIN tmpTableByUsrByDay T2 ON T2.Date >= T1.Date
AND T2.Date <= DATEADD(day, 4, T1.Date)
GROUP BY T1.User, T1.Date
)
备注:强>
- 它使用临时表,但可以使用公用表表达式(CTE),具体取决于底层SQL主机
- DateAdd()函数的特定名称/语法可能因SQL实现而异
- 这也意味着“日期”字段仅包含“日期”,即日期或日期时间/ smalldatetime,其中时间部分是固定的(比如说00:00)。如果不是这种情况,即如果数据库在列中有日期和时间,则可以在CTE / temp-table查询的级别修复。