2013-04-04 21 views
6

Powiedzmy, że istnieje tabela zawierająca tylko jedno pole. Tabela jest nazwany address i ma pole o nazwie ip który zawiera adres IPv4, jak jego wartościWyodrębnij pierwsze trzy oktety IPV4

Przykładowe dane

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 

muszę uruchomić zapytanie w tej tabeli, która będzie zwracać dane COUNT na pierwszym trzy oktety

oczekiwany wynik

Ilość sieć

192.168.120 5

192.168.121 3

Próbowałem za pomocą SUBSTR jak

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

Ale problemem jest to, że SUBSTR będzie działać tylko zgodnie z oczekiwaniami jeśli wszystkie pierwsze 3 oktety mają po 3 cyfry, ale będzie to działało na każdy adres ip, który nie ma 3 cyfr w pierwszym trzy oktety. Na przykład to nie będzie działać dla

192.168.0.0

192.2.3.50

192.23.4.60

Pytanie

Czy istnieje alternatywny do wyżej zapytanie, które będzie działać we wszystkich powyższych przypadkach?

Odpowiedz

8

Nie wykonuj operacji na ciągach. lepiej byłoby przekonwertować adresy IP na adresy int i użyć maski bitowej, np.

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

Wielkiej odpowiedzi, ale nadal trzeba przyciąć tylny oktet. –

+0

który byłby eksponatem. ponieważ ostatni oktet został wyzerowany, możesz pogrupować wynik wyniku inet. na przykład wszyscy byliby "x.x.x.0" –

+0

Dziękuję Marcowi za tę elegancką odpowiedź. Tak jak ty, spodziewałem się, że ten będzie działał szybciej niż dwie odpowiedzi podane poniżej. Jednak na tych samych danych zapytanie to trwa "0.28" sekundy, podczas gdy 'substring_index' zajmuje" 0,15 "sekundy. Czy jest jakiś haczyk, którego mi brakuje? –

5

Można użyć substring_index aby to zrobić:

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

Oto SQLFiddle przykład

+0

Dzięki Martin, Świetna odpowiedź. +1, wszystkie trzy podane odpowiedzi są poprawne, zdecydują o zaakceptowaniu na podstawie wydajności po przeprowadzeniu niektórych testów. –

+0

Podoba mi się ta odpowiedź, ze względu na jej prostotę. Można go łatwo rozszerzyć do 2 oktetów! – Laoneo

2

Sugerowałbym użyciu SUBSTRING_INDEX na to:

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

Dziękuję Mike za tę odpowiedź. +1 –