5

我正在尝试以 SQL 查询的形式为以下问题找到一个优雅的解决方案。

新记录将被插入到日志表中。我需要检测我以前从未见过的任何新记录(在过去一小时内插入)并生成警报(例如,这些记录的数量 > 0)

ID, Url, DOB
1, site1.com/page1, "5/06/2012 20:01"
2, site2.com/page2, "5/06/2012 21:20"
3, site1.com/page1, "6/06/2012 10:05"

如果“现在”是 6/06/2012 10:40 - 我看到插入了 1 条新记录 (id=3) 但我不想生成警报,因为我们之前已经看到过这个 URL (id=1) .

如果我们有 4, site3.com/pageX, "6/06/2012 10:08" 那么我想生成一个警报(返回计数 = 1),因为这一行是在最后一小时插入的,我们还没有看到它前。

实施它的最佳方法是什么?理想情况下没有嵌套查询

4

5 回答 5

5

我想这就是你所追求的。这将检索过去一小时内的新条目(其中 new 表示过去一小时未访问过相同的 URL)

SELECT  *
FROM    Log
WHERE   DOB > DATEADD(HOUR, -1, CURRENT_TIMESTAMP)
AND     NOT EXISTS
        (   SELECT  1
            FROM    Log T1
            WHERE   T1.URL = Log.URL 
            AND     T1.DOB < DATEADD(HOUR, -1, CURRENT_TIMESTAMP)
        )

SQL Fiddle上的工作示例

编辑

刚刚看到一个评论说你只需要一个计数:

SELECT  COUNT(*)
FROM    Log
WHERE   DOB > DATEADD(HOUR, -1, CURRENT_TIMESTAMP)
AND     NOT EXISTS
        (   SELECT  1
            FROM    Log T1
            WHERE   T1.URL = Log.URL 
            AND     T1.DOB < DATEADD(HOUR, -1, CURRENT_TIMESTAMP)
        )

编辑 2

我不知道为什么只需要一个选择,但是,我能得到的最接近一个选择的是:

SELECT  COUNT(*)
FROM    (   SELECT  *, MIN(DOB) OVER(PARTITION BY URL) [FirstViewed]
            FROM    Log
        ) Log
WHERE   FirstViewed >= DATEADD(HOUR, -1, CURRENT_TIMESTAMP)

如果同一页面在过去一小时内被访问过两次,这仍然会返回 2。

http://sqlfiddle.com/#!3/5a8bc/1

于 2012-06-07T13:10:48.053 回答
2

这个做一些替代,首先通过分组搜索唯一的 url,然后在最后一小时提取那些。

SELECT x1.*
FROM
  (SELECT URL,
          COUNT(ID) AS urlcount,
          MAX(DOB) AS uniqueurl
   FROM Log
   GROUP BY URL HAVING count(ID) = 1
   OR MIN(DOB) > dateadd(HOUR ,-1 , CURRENT_TIMESTAMP)) AS x1
WHERE x1.uniqueurl > dateadd(HOUR ,-1 , CURRENT_TIMESTAMP);

http://sqlfiddle.com/#!3/250e0/45/0

如果不查看解释,我无法确定这是否具有可接受的性能,但我认为 group by 中涉及的排序操作可能是一个瓶颈

于 2012-06-07T13:35:24.487 回答
1

没有嵌套查询(SQLFiddle):

SELECT COUNT(DISTINCT T0.URL) 
FROM Log AS T0 
LEFT OUTER JOIN Log AS T1 ON 
    T1.URL = T0.URL 
    AND T1.DOB < DATEADD(HOUR, -1, CURRENT_TIMESTAMP) 
WHERE 
    T0.DOB > DATEADD(HOUR, -1, CURRENT_TIMESTAMP) 
    AND T1.ID IS NULL

但它确实是与 GarethD 相同的解决方案,性能方面。

于 2012-06-07T13:45:17.060 回答
0

尝试这个:

SELECT DISTINCT a.id, a.url, a.dob
FROM Log a JOIN Log b ON (a.url = b.url)
WHERE UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(a.DOB)<=3600 
  AND UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(b.DOB)>3600;

它应该返回遵循您在问题中指定的模式的所有记录。

请注意,我使用UNIX_TIMESTAMP将日期转换为秒,因此减法将返回以秒数表示的时间差。并且必须与 3600 秒进行比较。

编辑

该语句已被更正。但它适用于 MySQL(我没有看到 sql-server2005 标签)

于 2012-06-07T12:58:59.557 回答
-1
select distinct(a.url) from tbl a, tbl b where a.dob>(now-hour) and b.dob<=(now-hour) and a.url=b.url; 

(用您选择的数据库中的某些内容替换时间操作。索引 url 和 dob)

还希望您的数据库足够明智,可以在加入和使用索引加入之前进行 dob 比较。

于 2012-06-07T12:46:26.023 回答