Поиск иерархического текста в базе данных Oracle - PullRequest
0 голосов
/ 27 октября 2011

Таблица = BLOCK (имеет составной уникальный индекс для обоих столбцов)

IP_ADDRESS   CIDR_SIZE
=========    ==========
10.10         16
15.0          16
67.7          16
18.0           8

Требования:

  • Подблок не допускается.Например, 67.7.1 и 24 не допускаются, так как это ребенок 67.7.Другими словами, если в базе данных есть какой-либо IP-адрес, который совпадает с начальной частью нового IP-адреса, он должен потерпеть неудачу.Могу ли я сделать это с помощью запроса Oracle SQL?

Я думал сделать это с помощью ...

  1. Выбрать все записи в памяти.
  2. Преобразование каждого IP в его двоичные биты

    10.10 = 00001010.00001010
    15.0 = 00001111.00000000
    67.7 = 01000011.00000111
    18.0 = 00010010.00000000

  3. Преобразование нового IP в двоичный бит.67.7.1 = 01000011.00000111.00000001

  4. Проверьте, начинаются ли новые двоичные биты IP с существующих двоичных битов IP.
  5. Если true, то новая запись существует в базе данных.Например, новый двоичный бит 01000011.00000111.00000001 начинается с существующих двоичных битов ip (67.7) 01000011.00000111.Остальные записи не совпадают.

Я смотрю, есть ли запрос Oracle, который может сделать это для меня, то есть вернуть соответствующие IP-адреса из базы данных.Я проверил текстовый API Oracle, но пока ничего не нашел.

Ответы [ 2 ]

0 голосов
/ 27 октября 2011

Да, вы можете сделать это в SQL, преобразовав IP-адреса в числа и убедившись, что это не запись с меньшим размером cidr, которая дает тот же ipnum при использовании его размера cidr.

WITH ipv AS
(   SELECT  IP.*
        ,   NVL(REGEXP_SUBSTR( ip, '\d+', 1, 1 ),0) * 256 * 256 * 256  -- octet1
        +   NVL(REGEXP_SUBSTR( ip, '\d+', 1, 2 ),0) * 256 * 256        -- octet2
        +   NVL(REGEXP_SUBSTR( ip, '\d+', 1, 3 ),0) * 256              -- octet3
        +   NVL(REGEXP_SUBSTR( ip, '\d+', 1, 4 ),0)  AS ipnum          -- octet4
        ,   32-bits                 AS ignorebits
    FROM  ips IP
)
SELECT  IP1.ip, IP1.bits
FROM    ipv IP1
WHERE   NOT EXISTS
    (   SELECT  1
        FROM    ipv IP2
        WHERE   IP2.bits < IP1.bits
        AND     TRUNC( IP2.ipnum / POWER( 2, IP2.ignorebits ) )
              = TRUNC( IP1.ipnum / POWER( 2, IP2.ignorebits ) )
    )

Примечание: мой пример использует таблицу, эквивалентную вашей:

SQL> desc ips
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 IP                                        NOT NULL VARCHAR2(16)
 BITS                                      NOT NULL NUMBER
0 голосов
/ 27 октября 2011

Есть ли причина, по которой вы не можете использовать функцию INSTR? http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions068.htm#i77598

Я бы сделал что-то вроде NOT EXISTS предложения, которое проверяет INSTR(b_outer.IP_ADDRESS,b_inner.IP_ADDRESS) <> 1

* edit: подумав об этом, вам, вероятно, придется проверить, равен ли результат 1 (имеется в виду, что потенциальный IP-адрес совпадает, начиная с первого символа существующего IP-адреса), в отличие от общего поиска по подстроке, поскольку I изначально было.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...