【问题标题】:MySQL Query for Returning New Visitors from Database用于从数据库返回新访问者的 MySQL 查询
【发布时间】:2011-04-01 06:26:58
【问题描述】:

假设我有一个记录传入用户的表,其中每个用户都有一个 IP 地址 (ipaddr)。

选择以前从未访问过该网站的所有用户的最佳方法是什么? (因此特定的 IPADDR 值只存在于表 once 中),但是我只想知道过去 6 小时内的新访客。

我基本上想在 SQL 中做这样的事情:

SELECT * from visitors GROUP BY ipaddr WHERE COUNT(ipaddr) = 1 and date > '2011-03-31 00:59:11'

但是,DATE 条件应该只适用于结果,而不是用于检查访问者是否是新的。

更新:

有一个 SID 字段用于说明用户浏览会话。

以下是相关的表架构:

CREATE TABLE `visitors` (
  `date` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `sid` bigint(12) unsigned NOT NULL,
  `ipaddr` int(8) NOT NULL,
)

一些示例数据:

INSERT INTO `visitors` (`date`,`sid`, `ipaddr`)
VALUES
    ('2011-03-31 06:25:48', 299521885457, -1454342140);


INSERT INTO `visitors` (`date`,`sid`, `ipaddr`)
VALUES
    ('2011-03-31 06:26:37', 299521885457, -1454342140);


INSERT INTO `visitors` (`date`,`sid`, `ipaddr`)
VALUES
    ('2010-01-01 15:23:44', 694387538590, -1454342140);

此访问者有两行实时发生的当前会话,每一行是他访问过的每个页面(仅显示相关架构)。最后显示的示例行是 2010 年的访问,这意味着该 IP 地址有 2 个不同的 SID 属于它,因此不是新访问者。

查询的结果应该没有上面列出的任何行,因为这个访问者在数据库中有两个会话。如果最后一行被删除(sid 694387538590),访问者应该成为新访问者并出现在查询中。

【问题讨论】:

    标签: mysql optimization


    【解决方案1】:

    GROUP BY"WHERE"HAVING

    SELECT ipaddr from visitors
    GROUP BY ipaddr
    HAVING COUNT(ipaddr) = 1 AND MIN(date) > '2011-03-31 00:59:11'
    

    更新

    SELECT ipaddr, max(sid) sid
      FROM visitors
     GROUP BY ipaddr
    HAVING     COUNT(DISTINCT sid) = 1
           AND MIN(date) > '2011-03-31 00:59:11'
    

    说明:

    SELECT date, sid, ipaddr FROM visitors
    
    date                sid        ipaddr 
    ------------------------------------------
    2011-03-31 06:25:48 299525457  -1454342140 
    2011-03-31 06:26:37 299525457  -1454342140 
    2010-01-01 15:23:44 694388590  -1454342140 
    2011-03-31 11:23:44 111111111  -1234444811 
    2011-03-31 12:23:44 111111111  -1234444811
    
    SELECT ipaddr FROM visitors GROUP BY ipaddr
    
    ipaddr
    -----------
    -1454342140 
    -1234444811 
    
    --- group for ip -1454342140 ---
    
    2011-03-31 06:25:48 299525457  -1454342140 
    2011-03-31 06:26:37 299525457  -1454342140 
    2010-01-01 15:23:44 694388590  -1454342140
    
    COUNT(DISTINCT sid) = COUNT(299525457, 694388590) = 2
    --> there is more than 1 session for this ip: not good!!!
    
      ==> group discarded
    
    --- group for ip -1234444811 ---
    
    2011-03-31 11:23:44 111111111  -1234444811 
    2011-03-31 12:23:44 111111111  -1234444811
    
    COUNT(DISTINCT sid) = COUNT(111111111) = 1 --> OK
    (here COUNT(sid) = count(111111111, 111111111) = 2
     --> despite it is the same sid, the count is 2, that is why using DISTINCT)
    
    MIN(date) = '2011-03-31 11:23:44' > '2011-03-31 00:59:11' --> OK
    
      ==> group accepted
    

    SELECT 中的授权列是:

    • GROUP BY 子句中使用的列
    • 其他列的聚合

    ipaddr 在 GROUP BY 中使用,但不是 sid。还有 sid 我使用了 MAX 但请记住,它将仅应用于当前 ipaddr 的行组,并且由于查询中的条件有 1 个唯一的 sid 但重复所以结果将是sid

    【讨论】:

    • 嗯,这似乎符合我的描述。你能解释一下这个查询是如何工作的吗?我认为 GROUP BY 在 HAVING 之前应用,因此 GROUP by 将在每个 ipaddr 留下 1 行。那么,对于 GROUP BY 之后剩下的所有行,count(ipaddr) 不会等于 1 吗?
    • HAVING 子句用于过滤聚合(SUM、COUNT、AVG),WHERE 子句过滤条件。所以它会先进行 GROUP BY,然后将不满足 HAVING 条件的记录全部剔除。
    • HAVING 子句与聚合函数一起使用以过滤由GROUP BY 生成的组,即:在返回ipaddr 之前,count(ipaddr) = 1 针对具有ipaddr 的行组进行评估
    • 谢谢大家,这很有帮助!
    • 在 IPADDR 上建立索引是否有意义,或者 HAVING 可以不使用该索引?
    猜你喜欢
    • 1970-01-01
    • 2020-08-04
    • 2011-04-08
    • 2017-02-27
    • 2012-10-21
    • 2012-12-15
    • 2016-09-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多