2011-10-27 79 views
0

表= 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地址。我檢查了Oracle的Text API,但還沒有發現任何東西。

回答

0

有沒有理由不能使用INSTR功能? http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions068.htm#i77598

我會做這樣的事情檢查INSTR(b_outer.IP_ADDRESS,b_inner.IP_ADDRESS) <> 1

一個NOT EXISTS條款*編輯:思考這個你可能會需要進行檢查,看如果結果是1(意味着潛在的IP地址匹配從現有IP地址的第一個字符開始),而不是像我原來的一般子字符串搜索。

+0

INSTR不會工作,如果比特的數量不上的8例如因子重疊'10.224/11'是'10.240/12'的父母,但不是'10.176/12' – Sodved

+0

謝謝。我不介意在保留ip_address作爲二進制位格式的表中添加另一列,如果這有助於我僅使用查詢來實現這一點,那麼可能與LIKE子句相反。 – Sannu

0

是的,你可以通過將IP轉換爲數字,然後確保這不是具有較小的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