在多个表中使用SUM会产生意外结果

时间:2014-08-11 19:45:55

标签: mysql sum

我对数据库查询并不熟悉,似乎找不到我想要的东西。

我有一个简单的数据库,包含2个表,log和block。

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       |       | 
+-------+-------------+------+-----+---------+-------+

我的问题是这个。运行以下查询时,sum(cnt)会产生意外结果。

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地址,但显示反向似乎是在逃避我。

我还有一些要构建的查询,我想如果我可以让这个人工作,其余的应该落实到位。

任何帮助将不胜感激。 谢谢。

更新: 除了SUM仍然关闭之外,这个工作正常。其他一切看起来都不错。注意我删除了一两行,以便于测试。

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;

1 个答案:

答案 0 :(得分:0)

正如xQbert所提到的那样,你通过FROM block, log进行交叉联接,它为log中的每一行提供block中的行。然后你把它们中的一些过滤掉了,但是你仍然有比以前更多的行。

解决方案将是一个子选择。

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

或者您可以使用子选择创建要加入的第三个表:

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