问题描述
我有一张图表,显示了按日期(今天每小时)基于 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]
更新问题的最后一部分;
-
您当前的查询是一致的。您显示不同 ip 和会话的计数,但您的 have 子句并未反映这一点。您的 Have 子句按日期和 ip 分组计数。我不确定你是否故意这样做。也许你的 have 子句应该是
having count(distinct ip,session_id)>1
。 -
对于您的最终结果集,无需修改您的最终查询,将其用作子查询,如
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 作为单个唯一字符串。 另一个问题是对日期和小时进行分组。所以这里是一步一步:
-
创建基础参考数据:
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() 作为来自 ( 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
-
如果您使用的是 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
-
您正在用您所说的 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:抱歉,无法进行格式化。