2013-04-04 12 views
6

Diciamo che c'è una tabella con un solo campo. Tabella è chiamato address e ha un campo denominato ip che contiene un indirizzo IPv4 come valoreEstratto 1st Three Octets di un IPV4

dei dati di campionamento

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 

Ho bisogno di eseguire una query su questa tabella che restituirà i dati COUNT su The First tre ottetti

output previsto

conteggio rete

192.168.120 5

192.168.121 3

Ho provato ad utilizzare SUBSTR come

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

Ma il problema è che questo SUBSTR funziona solo come previsto se tutti i primi 3 ottetti hanno 3 cifre ciascuno, ma questo si interromperà su qualsiasi indirizzo IP che non ha 3 cifre ciascuno in prima tre ottetti Per esempio questo non funziona per

192.168.0.0

192.2.3.50

192.23.4.60

Domanda

C'è qualche alternativa a quanto sopra query che funzionerà in tutti i casi precedenti?

risposta

8

Non eseguire operazioni con le stringhe. staresti meglio convertendo gli IP in int e usando qualche maschera di bit, ad es.

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

Grande risposta, ma è ancora bisogno di tagliare l'ottetto finale. –

+0

sarebbe una cosa da esposizione. dato che l'ottetto finale è stato azzerato, puoi raggruppare il risultato della trasformazione inet. per esempio. sarebbero tutti 'x.x.x.0' –

+0

Grazie Marc per questa risposta elegante. Proprio come te, mi aspettavo che questo si esibisse più velocemente delle due risposte fornite di seguito. Comunque sugli stessi dati questa query richiede '0.28' secondi mentre quella' substring_index' sta prendendo '0.15' secondi. C'è qualche presa che mi manca? –

5

Si potrebbe utilizzare substring_index per fare questo:

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

Ecco un SQLFiddle esempio

+0

Grazie Martin, ottima risposta. +1, tutte e tre le risposte date sono valide, deciderà quella accettata in base alle prestazioni dopo aver eseguito alcuni test –

+0

Mi piace questa risposta, a causa della sua semplicità. Può essere esteso facilmente a 2 ottetti! – Laoneo

2

Io suggerirei di usare SUBSTRING_INDEX per questo:

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

Grazie Mike per questa risposta. +1 –