2013-04-04 69 views
6

假設有一個只有一個字段的表格。表被命名爲address,有一個名爲ip字段,它包含一個IPv4地址作爲其值提取IPV4的前三個字節

樣本數據

192.168.120.201 
192.168.120.202 
192.168.120.203 
192.168.120.204 
192.168.120.205 
192.168.121.3 
192.168.121.50 

我需要運行在此表的查詢,將在第一個返回數據COUNT三個八位位組

期望輸出

網絡計數

192.168.120 5

192.168.121 3

我嘗試使用SUBSTR

SELECT SUBSTR(ip,1,10) as network,COUNT(*) as c FROM address GROUP BY network HAVING(c>1) 

但問題是,由於預計今年SUBSTR只會工作如果前3個八位字節每個都有3位數字,但這將在任何第一個沒有3位數字的IP地址中斷三個八位字節。例如,這將不會爲

192.168.0.0

192.2.3.50

192.23.4.60

問題

工作是否有任何替代上述查詢哪些可以在上面的所有情況下工作?

回答

8

不要做字符串操作。您最好將IP轉換爲整數並使用一些位掩碼,例如

SELECT INET_NTOA(INET_ATON(ipfield) & 0xFFFFFF00) 
+0

偉大的答案,但你仍然需要修剪結尾的八位字節。 – 2013-04-04 16:51:15

+0

這將是一個顯示的東西。由於最終八位字節已被清零,因此可以對inet變換的結果進行分組。例如他們都是'x.x.x.0' – 2013-04-04 16:54:34

+0

謝謝馬克這個優雅的答案。就像你一樣,我期望這個比下面給出的兩個答案更快。然而,在相同的數據上,這個查詢花費了0.28秒,而substring_index花費了0.15秒。我錯過了什麼? – 2013-04-04 17:20:53

5

你可以使用substring_index做到這一點:

SELECT substring_index(network, '.', 3) AS Octet, 
     COUNT(*) 
    FROM address 
    GROUP BY Octet 

這裏有一個SQLFiddle例如

+0

謝謝馬丁,很好的答案。 +1,所給出的三個答案都是有效的,將在運行一些測試後根據性能決定接受的答案 – 2013-04-04 17:23:11

+0

我喜歡這個答案,因爲它很簡單。它可以很容易地擴展到2個八位字節! – Laoneo 2015-03-02 10:07:03

2

我會使用SUBSTRING_INDEX此建議:

SELECT SUBSTRING_INDEX(ip, '.', 3) as network, COUNT(*) as c 
FROM address 
GROUP BY network 
HAVING(c>1) 
LIMIT 500 
+0

感謝邁克這個答案。 +1 – 2013-04-04 17:23:48