2010-06-15 16 views
1

J'ai une table MySQL où je stocke des plages IP. Il est configuré de la façon dont j'ai l'adresse de début stockée en tant que long, et l'adresse de fin (et un ID et d'autres données). Maintenant, j'ai des utilisateurs qui ajoutent des plages en entrant une adresse IP de début et de fin, et je voudrais vérifier si la nouvelle plage n'est pas déjà (partiellement) dans la base de données.Comparer la plage d'adresses IP avec l'adresse IP de début et de fin dans MySQL

Je sais que je peux faire entre la requête, mais cela ne semble pas fonctionner avec 2 colonnes différentes, et je ne peux pas non plus comprendre comment passer une gamme pour le comparer. Le faire dans une boucle en PHP est une possibilité, mais serait avec une gamme de p. 132.0.0.0-199.0.0.0 une assez grande quantité de requêtes ..

Répondre

2

Lorsque vous dites que vous avez les adresses stockées comme long, je suppose que vous vous entendez les avez stockés de telle sorte que (disons) 10.1.2.3 sera stocké sous la forme 0x0a010203. Dans ce cas, pour trouver si une adresse est déjà présente, vous pouvez le faire:

SELECT ... 
FROM ipranges 
WHERE (<NEWADDR> >= startaddr) 
    AND (<NEWADDR> <= endaddr) 

et si vous obtenez toutes les lignes arrière, l'adresse est déjà dans le tableau. (Remplacer <NEWADDR> avec la nouvelle adresse, bien sûr!)

En ce qui concerne la vérification des lignes qui se chevauchent, qui est seulement un peu plus compliqué:

SELECT ... 
FROM ipranges 
WHERE NOT ((<NEWENDADDR> < startaddr) OR (<NEWSTARTADDR> > endaddr)) 

-à-dire la nouvelle gamme ne se chevauchent pas l'ancienne gamme à condition que ce soit elle commence après, ou se termine avant.

+0

la logique de chevauchement était un peu trop lourde, semble-t-il, pour moi maintenant, merci pour l'aide. J'avais déjà pensé à une belle boucle en PHP qui n'était pas trop inefficace mais c'est beaucoup plus rapide encore ofcourse – Maarten

0

Qu'en est-il quelque chose comme:

SELECT * FROM addresses WHERE 
    (start < $new_start AND end > $new_start) OR 
    (start > $new_end AND end < $new_end); 

Cela devrait vous donner toutes les adresses existantes qui chevauchent la nouvelle adresse.

+0

si la nouvelle gamme entoure complètement l'ancienne gamme? Par exemple, si ancienne gamme était (début = 99, fin = 100) et la nouvelle gamme est ($ new_start = 1, $ new_end = 200)? Je ne pense pas que votre requête retournerait ce résultat :-( – psmears

+0

donc il est un simple clause additionnelle: 'OR (start> = $ new_start et à la fin <= $ new_end)' –

1

Les deux start_address et end_address sont longues? Alors pourquoi ne pas simplement convertir l'IP que vous cherchez à faire longtemps et faire WHERE start_address <= $myip AND end_address >= $myip?

Pour une gamme, il suffit de faire trois fois dans la clause where

WHERE (start_address <= $startAddress AND end_address >= $startAddress) 
    OR (start_address <= $endAddress AND end_address >= $endAddress) 
    OR (start_address >= $startAddress AND end_address <= $endAddress) 

Le premier groupe trouve des plages qui entourent l'adresse de départ. Le second trouve des plages qui englobent l'adresse de fin. Cela signifie qu'il est toujours possible que la plage qui a été entrée soit un surensemble d'une plage dans la base de données. C'est ce que le troisième vérifie.

Cela devrait vous retourner toutes les gammes qui se croisent votre gamme ... entrée

+0

Vous ne avez pas réellement besoin de trois cas - il est plus facile de vérifier les cas où les intervalles * ne se chevauchent pas (c.-à-d.la nouvelle gamme est soit entièrement inférieure, soit entièrement supérieure à la gamme existante), puis utilisez 'NOT' pour inverser le résultat :-) – psmears

1

Comment sur le stockage des addres IP varie en décimal de cette façon que vous pouvez faire des contrôles simples à l'aide BETWEEN.

4294967295-4294967040 -> ffffff00 - FFFFFFFF -> 255.255.255.0 - 255.255.255.255