0

我有一个图表,按日期(今天每小时)显示基于 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 的表中。 Returning 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], ip, count(distinct ip, 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
4

1 回答 1

0

您可以通过对 IP 进行分组并过滤计数超过一个的 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 和会话的计数,但您的 having 子句并未反映这一点。您的 Have 子句按日期和 ip 分组计数。我不确定你是否故意这样做。也许你的having子句应该是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. 按我的独特价值和日期 - 小时查找退货商品:

    select dt_H,uniq,count( ) as times from ( 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) ) 作为辅助组由 dt_H,uniq 具有 count( )>1

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

    选择不同的returning.dt_H,main.[sid],main.[ip],returning.times from [mytable] 作为主内连接( select dt_H,uniq,count(*) as times from ( SELECT FORMAT(dt, 'yyyy -MM-dd HH') 作为 dt_H, [sid]+':'+[ip] 作为 uniq

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

    ) 作为返回返回.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:抱歉无法进行格式化。

于 2021-02-04T19:04:18.483 回答