我有一个postgres数据库,其中包含带有IP,用户和时间字段的表。我需要查询以提供在一个定义的时间段内只有一个用户活跃的所有IP的完整集合(即,我需要过滤出多个或没有用户的IP,并且每个IP仅包含一行) 。用户字段包含一些我可以过滤掉的空值。我正在使用Pandas的read_sql()方法直接获取数据框。
我可以轻松地从定义的时间段获取数据的完整数据帧:
SELECT ip, user FROM table WHERE user IS NOT NULL AND time >= start AND time <= end
然后我可以使用带有groupby和filter操作的熊猫轻松地获取这些数据并将所需的信息弄乱。但是,我希望能够使用单个SQL查询获得所需的信息。不幸的是,我的SQL排不太热。我在下面的第一次尝试不是很好;我最终得到的数据框与使用上面的原始查询和一些熊猫争吵手动创建数据框时不同。
SELECT DISTINCT ip, user FROM table WHERE user IS NOT NULL AND ip IN (SELECT ip FROM table WHERE user IS NOT NULL AND time >= start AND time <= end GROUP BY ip HAVING COUNT(DISTINCT user) = 1)
有人可以在这里向我指出正确的方向吗?谢谢。
edit :我忽略了提及每个用户/ ip组合有多个条目的情况。来源是网络身份验证流量,用户非常频繁地在IP上进行身份验证。
样品台头:
---------------------------------
ip | user | time
---------------------------------
172.18.0.0 | jbloggs | 1531987000
172.18.0.0 | jbloggs | 1531987100
172.18.0.1 | jsmith | 1531987200
172.18.0.1 | jbloggs | 1531987300
172.18.0.2 | odin | 1531987400
如果要查询此示例表中的时间范围1531987000到1531987400,我需要以下输出:
---------------------
ip | user
--------------------
172.18.0.0 | jbloggs
172.18.0.2 | odin
答案 0 :(得分:1)
这应该有效
SELECT ip
FROM table
WHERE user IS NOT NULL AND time >= start AND time <= end
GROUP BY ip
HAVING COUNT(ip) = 1
说明:
SELECT ip FROM table WHERE user IS NOT NULL AND time >= start AND time <= end
-筛选出空值和时间段
...GROUP BY ip HAVING COUNT(ip) = 1
-如果一个IP有多个用户,则该IP的计数(该IP的行数)将大于1。
答案 1 :(得分:0)
如果“单用户”是指可能只有一个用户的多行,那么:
SELECT ip
FROM table
WHERE user IS NOT NULL AND time >= start AND time <= end
GROUP BY ip
HAVING MIN(user) = MAX(user) AND COUNT(user) = COUNT(*);
答案 2 :(得分:0)
我想出了一个查询,可以查询到我想要的东西:
SELECT DISTINCT ip, user
FROM table
WHERE user IS NOT NULL AND time >= start AND time <= end AND ip IN
(SELECT ip FROM table
WHERE user IS NOT NULL AND time >= start AND time <= end
GROUP BY ip HAVING COUNT(DISTINCT user) = 1)
说明:
内部选择使我在指定的时间范围内只有一个用户的所有IP。然后,我需要从主表中选择IP /用户对,而IP在嵌套选择中。
尽管我必须两次(时间范围和非空用户字段)进行相同的过滤,这看起来很混乱,有没有更好的方法呢?