用于在一段时间内找到最大项目的算法建议

时间:2010-03-18 19:39:36

标签: mysql sql

我有一个类似于以下内容的数据库架构:

| 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:另一个有前途的解决方案。也看起来很复杂,但我会再看一遍

再次感谢!

4 个答案:

答案 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查询的级别修复。