Mysql 将SUM与多个表一起使用会产生意外的结果
我对数据库查询没有真正的经验,似乎找不到我要找的东西 我有一个简单的数据库,有两个表,log和blockMysql 将SUM与多个表一起使用会产生意外的结果,mysql,sum,Mysql,Sum,我对数据库查询没有真正的经验,似乎找不到我要找的东西 我有一个简单的数据库,有两个表,log和block Log: +----------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+------------------+------+-----+----
Log:
+----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| srcip | varchar(25) | NO | | NULL | |
| dstip | varchar(25) | NO | | NULL | |
| cnt | int(10) unsigned | NO | | NULL | |
+----------+------------------+------+-----+---------+----------------+
Block:
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| ip | varchar(25) | YES | | NULL | |
| shun | int(11) | NO | | NULL | |
| count | int(11) | NO | | 0 | |
+-------+-------------+------+-----+---------+-------+
我的问题是这个。运行以下查询时,sumcnt会给出意外的结果
SELECT DISTINCT srcip, SUM(cnt) as hitcnt, COUNT(DISTINCT dstip) as dstcnt
FROM block,log
WHERE (dstip LIKE '10.10.10.%'
AND block.ip != srcip
AND srcip NOT LIKE '$restricted'
AND time >= DATE_SUB(NOW(), INTERVAL $start_units $units)
AND time <= DATE_SUB(NOW(), INTERVAL $end_units $units))
GROUP BY srcip
ORDER BY hitcnt, INET_ATON(srcip) asc;"
如果运行相同的查询并删除日志表和引用它的语句,则每个IP地址的总和是正确的。使用这两个表的原因是,我只想显示未被阻止的IP地址。阻止的IP信息包含在阻止表中。我已经知道如何使用这两个表只显示被阻止的IP地址,但我似乎无法显示相反的IP地址
我还有几个问题需要解决,我想如果我能解决这个问题,其余的问题都会解决
任何帮助都将不胜感激。
多谢各位
更新:
这是可行的,除非总数还没有确定。其他一切看起来都很好。注:我删除了一两行代码,以保持测试的简单性
SELECT DISTINCT srcip, SUM(cnt) as hitcnt, COUNT(DISTINCT dstip) as dstcnt
FROM log a JOIN block b
ON a.srcip != b.ip
WHERE (dstip LIKE '10.10.10.%'
AND time >= DATE_SUB(NOW(), INTERVAL 1 hour)
AND time <= DATE_SUB(NOW(), INTERVAL 0 hour)
AND srcip != ip)
GROUP BY srcip
HAVING hitcnt >= '2' AND dstcnt >= '2'
ORDER BY hitcnt, INET_ATON(srcip) ASC;
我明白了!!我知道你们会引导我走向正确的方向。谢谢大家的帮助
SELECT DISTINCT srcip, SUM(cnt) as hitcnt, COUNT(DISTINCT dstip) as dstcnt
FROM log a LEFT JOIN block b
ON srcip = ip
WHERE (dstip LIKE '10.10.10.%'
AND time >= DATE_SUB(NOW(), INTERVAL $start_units $units)
AND time <= DATE_SUB(NOW(), INTERVAL $end_units $units))
GROUP BY srcip
HAVING hitcnt >= '2' AND dstcnt >= '2'
ORDER BY hitcnt, INET_ATON(srcip) ASC;
正如xQbert所提到的,您可以通过FROM块log进行交叉连接,这会在块中有行的情况下,提供来自log的每一行。然后过滤掉其中的一些行,但仍有比以前更多的行 一个解决方案是子选择
SELECT DISTINCT log.srcip,
(SELECT SUM(cnt) FROM log WHERE log.srcip = srcip) as hitcnt, COUNT(DISTINCT dstip) as dstcnt
FROM block,log
WHERE (dstip LIKE '10.10.10.%'
AND block.ip != srcip
AND srcip NOT LIKE '$restricted'
AND time >= DATE_SUB(NOW(), INTERVAL $start_units $units)
AND time <= DATE_SUB(NOW(), INTERVAL $end_units $units))
GROUP BY srcip
ORDER BY hitcnt, INET_ATON(srcip) ASC
或者,您可以使用subselect创建要与之联接的第三个表:
SELECT DISTINCT log.srcip, hitcnt, COUNT(DISTINCT dstip) as dstcnt
FROM block,log,(SELECT srcip, SUM(cnt) as hitcnt FROM log GROUP BY srcip) t
WHERE (dstip LIKE '10.10.10.%'
AND block.ip != log.srcip
AND log.srcip = t.srcip
AND log.srcip NOT LIKE '$restricted'
AND time >= DATE_SUB(NOW(), INTERVAL $start_units $units)
AND time <= DATE_SUB(NOW(), INTERVAL $end_units $units))
GROUP BY log.srcip
ORDER BY hitcnt, INET_ATON(srcip) ASC
您的连接是交叉连接块中的所有行*日志中的所有行。这些事实上是如何相互关联的?块IP与srcIP相关,还是块IP与dstip相关?或者两者都有,或者什么?而不是将块中的这1行与日志中的这5行绑定。1行绑定到日志中的每一行。这会人为地增加计数和计数之和。日志表保存所有活动的日志。block表包含已被阻止的srcip地址。一旦它们被添加到块表中,它们就停留在那里。sun列显示它们当前是否被阻止。计数列是它们被阻止的次数。其想法是只报告当前未被阻止的SRIP。有两种方法可以显示被阻止的IP。1、用所有时间计数显示所有阻塞,2、用tact中的所有其他标志显示阻塞报告。谢谢。我两个问题都无法解决。。。然而第一个显示所有的计数相同。第二个抛出一个错误。不过没关系,这是个开始,我很感谢你的意见。我今天要摆弄一下。非常感谢。我没有时间测试它。同样的计数?你是说同一个国家?第一个查询也应该如此。secound one中的错误可能是第1、4、5和9行中的srcip不是唯一的,因此您必须使用log.srcip代替标题。我明白了,请参见顶部的“我的编辑”。没有你的帮助,我不可能做这件事。正如我所说,我只是需要一个指向正确方向的点。谢谢