SQL:按日期计算基于 IP 组的回访者和新访问者

问题描述

我有一张图表,显示了按日期(今天每小时)基于 IP 组的唯一身份访问者。

现在我想根据 IP 和 session_id 将这些数据分开给新访问者和回访者,并按日期(今天每小时)对它们进行分组。如何使用 sql 查询执行此操作?甚至有可能吗?

如果带有 session_id 的 IP 已经存在,则查询应该在表中查找。然后是回访者。否则就是新访客。我不知道该怎么做。

查询我今天必须计算唯一 IP 并按每小时对它们进行分组:

SELECT disTINCT DATE_FORMAT(`date`,'%Y-%m-%d %H') as 'dates',COUNT(disTINCT `ip`) as 'count' FROM `logging` WHERE DATE(date) = DATE(Now()) GROUP BY `dates`

现在它向我展示:

Dates            Count
2021-02-04 00    10
2021-02-04 01    8
2021-02-04 02    5

我想要的是:

Dates            Count new IP      Count returning IP
2021-02-04 00    2                 8
2021-02-04 01    4                 4
2021-02-04 02    2                 3

新 IP:检查 IP 是否存储在只有一个已知 session_id 的表中。 返回IP:检查IP 是否存储在具有多个不同session_id 的表中。

非常感谢!

更新 #1:

现在我有以下查询来计算今天的回访者:

SELECT date,ip,count(distinct ip,session_id) as 'count' FROM logging GROUP BY ip HAVING count > 1 AND date(date) = date(Now())

结果例如:

date                    ip                   count (returning visitors)
2021-02-05 08:24:56     62.163.91.178        2
2021-02-05 10:24:15     77.163.91.223        6
2021-02-05 08:49:51     77.173.17.157        13

如何更改此查询以按日期对它们进行分组以获取此信息?:

date                    count (returning visitors)
2021-02-05 08           15
2021-02-05 10           6

更新 #2:

感谢 Tsungur,我得到了以下查询,但每次运行它都会显示不同的结果。

select DATE_FORMAT([date],'%Y-%m-%d %H') as [date],count(*) from ( SELECT [date],session_id) as 'count' FROM logging GROUP BY ip HAVING count(distinct ip,session_id) > 1 AND date(date) = date(Now())
) as sub
group by DATE_FORMAT([date],'%Y-%m-%d %H') 

这里有一些数据可以玩:

ID        session_id                   ip               date
10752     454747k5k45l23h3b5n6k432nn   44.56.123.123    2021-01-01 09:15:54   
10950     kmcoq3glgm187uhsfmo3r71h9q   86.85.131.246    2021-02-11 13:19:22
10958     kmcoq3glgm187uhsfmo3r71h9q   86.85.131.246    2021-02-12 12:10:52
10960     dfh78dfh7fdh7fdh6sd55dsd88   86.85.131.246    2021-02-12 13:00:02
10967     87s97sfh57sh6sh6s6sdsd44d3   11.56.873.560    2021-02-13 13:00:00
10968     rkdrgjsd7gjsd5jskjd46kjdsk   66.35.127.435    2021-02-13 13:01:00
10977     rkdrgjsd7gjsd5jskjd46kjdsk   66.35.127.435    2021-02-13 13:03:11
10978     dfajesj9sdj0dfh78sgd57sd5d   44.56.123.123    2021-02-13 13:05:12
10979     fhdf7f7hdf6fd44fdf3ffdf321   86.85.131.246    2021-02-13 14:05:02
10980     fhdf7f7hdf6fd44fdf3ffdf321   86.85.131.246    2021-02-13 14:06:13

以上数据应该告诉我:

date             count (new visitor)
2021-02-13 13    2
2021-02-13 14    0

date             count (returning visitor)
2021-02-13 13    1
2021-02-13 14    1

解决方法

您可以通过对 IP 进行分组并过滤计数超过 1 的 IP 来查找返回的 IP。

SELECT [ip]
FROM [logging]
group by [ip]
having count(*)>1

然后您可以将此查询用作主查询的过滤器。

SELECT [ip],[date],count(*) as [Count]
FROM [logging]
where [ip] in
(
SELECT [ip]
FROM [logging]
group by [ip]
having count(*)>1
)
group by [ip],[date]

更新问题的最后一部分;

  1. 您当前的查询是一致的。您显示不同 ip 和会话的计数,但您的 have 子句并未反映这一点。您的 Have 子句按日期和 ip 分组计数。我不确定你是否故意这样做。也许你的 have 子句应该是 having count(distinct ip,session_id)>1

  2. 对于您的最终结果集,无需修改您的最终查询,将其用作子查询,如

    select DATE_FORMAT([date],'%Y-%m-%d %H') as [date],count(*) from (
    SELECT [date],ip,count(distinct ip,session_id) as 'count' FROM logging GROUP BY ip HAVING count > 1 AND date(date) = date(now())
        ) as sub
        group by DATE_FORMAT([date],'%Y-%m-%d %H') 
    

更新 #2 首先是一些建议,如果可能,不要使用保留字作为列名(例如日期)。 我试图把问题分解成碎片。最终查询看起来很脏,可以改进和缩短。但是为了澄清问题,我使用了多个查询。您的第一个问题是计算唯一的 sid 和 ip。为简单起见(因为两者都是字符串),我使用 sid+':'+ip 作为单个唯一字符串。 另一个问题是对日期和小时进行分组。所以这里是一步一步:

  1. 创建基础参考数据:

         SELECT FORMAT(dt,'yyyy-MM-dd HH') as dt_H,[sid]+':'+[ip] as uniq
    
       FROM [mytable]
       where cast(dt as date)=cast(getdate() as date)
    
  2. 按我的唯一值和日期 - 小时查找退货商品:

    选择 dt_H,uniq,count() 作为来自 ( SELECT FORMAT(dt,'yyyy-MM-dd HH') 作为 dt_H,[sid]+':'+[ip] 作为 uniq 来自 [mytable] where cast(dt as date)=cast(getdate() as date) ) 作为帮手 按 dt_H,uniq 分组 有 count()>1

  3. 如果您使用的是 php,您可以稍后通过 : 字符分隔 uniq 字段。但是如果你想在 sql 中使用它,我们将在没有区分列的情况下加入主表:

    选择不同的returning.dt_H,main.[sid],main.[ip],returning.times from [mytable] as main 内部联接 ( 选择 dt_H,count(*) 作为时间 从 ( SELECT FORMAT(dt,[sid]+':'+[ip] 作为 uniq

           FROM [mytable]
           where cast(dt as date)=cast(getdate() as date)
     ) as helper
       group by dt_H,uniq
       having count(*)>1
    

    ) 作为返回 在returning.uniq=main.[sid]+':'+main.[ip] 和FORMAT(main.dt,'yyyy-MM-dd HH')=returning.dt_H

  4. 您正在用您所说的 PHP 填补空白。您也可以在 sql 中执行此操作。我建议创建一个用户定义的函数(它在很多时候都派上用场),它将在给定范围内创建数值: CREATE FUNCTION [dbo].[GetNumbers](@Start int,@Stop int) RETURNS TABLE AS RETURN WITH Numbers (N) AS ( SELECT @Start UNION ALL SELECT @Start + N-@Start+1 FROM Numbers WHERE N < @Stop ) SELECT N FROM Numbers GO

用法:

SELECT N FROM [dbo].[GetNumbers] (0,23)

这将返回一个包含一天中所有小时数的表。您可以使用此表,结合日期部分和左连接与上述查询。因此,如果为空,您可以显示所有小时数和 0 返回时间。

PS:抱歉,无法进行格式化。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...