在Oracle数据库中搜索分层文本

时间:2011-10-27 14:41:58

标签: java oracle

表= 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开始。其余记录不匹配。
  6. 我正在查看是否有可以为我执行此操作的Oracle查询,即从数据库返回匹配的IP地址。我检查了Oracle的Text API,但还没有找到任何东西。

2 个答案:

答案 0 :(得分:0)

你有没有理由不能使用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子句

*编辑:考虑到这一点,您可能需要检查结果是否为1(意味着潜在的IP地址与现有IP地址的第一个字符匹配),而不是一般的子字符串搜索。最初有它。

答案 1 :(得分:0)

是的,您可以通过将IP转换为数字来在SQL中执行此操作,然后确保这不是具有较小cidr大小的记录,在使用其cidr大小时提供相同的ipnum。

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