Search code examples
oracle-databaseplsqlclob

Extract CLOB data for insert


I have CLOB data like this:

123456 (LED TV); 234543 (LED light); 654876 (LED monitor);

Now I need to extract all 6-digit numbers (invoice tracking number in my case) from CLOB using delimiter ( in my case ";" ) and select that for Insert into target table but only If record doesn't exist.

I've seen couple of examples with Instr & Substr or Regexp, but nothing what I need or beyond my understanding of Oracle. Can somebody show me an example of how to split CLOB into rows based on string inside CLOB, to make use of It for later Insert ?

P.S.: I would prefer fastest solution since my CLOB data could contain over 5 million of invoice records. It's going to be a stored procedure fired from C# at the end, but this part is causing me headaches... For any help - thanks in advance !


Solution

  • I have tried to complete the task using DBMS_LOB package to convert them to strings divided by ";" and then did some string operations on it to achieve the result.

    Try following:

    INSERT INTO INVOICE_CATEGORIZED 
    SELECT TAB.INVOICE_NUMBER, TAB.INVOICE_NAME FROM
    (SELECT 
    TRIM(dbms_lob.SUBSTR(INVOICE_INN,6 ,1)) AS INVOICE_NUMBER, 
    
    SUBSTR(INVOICE_INN, 
    INSTR(INVOICE_INN, '(') + 1,
    INSTR(INVOICE_INN, ')') - INSTR(INVOICE_INN, '(') - 1 )
     AS INVOICE_NAME
    
    -- HERE INVOICE_INN IS STRING NOW, SO WE CAN DO STRING OPERATIONS ON IT ONWARD
    
    FROM
    (
    -- DIVIDING ; SEPARATED CLOB TO INDIVIDUAL STRING
    SELECT
        TRIM(CASE WHEN INVOICE_SINGLE.COLUMN_VALUE = 1 THEN
        dbms_lob.SUBSTR(INVOICE, 
        dbms_lob.INSTR(INVOICE,';',1,INVOICE_SINGLE.COLUMN_VALUE) - 1,
        1 
        )
        ELSE
        dbms_lob.SUBSTR(INVOICE, 
        dbms_lob.INSTR(INVOICE,';',1,INVOICE_SINGLE.COLUMN_VALUE) - 1
        - dbms_lob.INSTR(INVOICE,';',1,INVOICE_SINGLE.COLUMN_VALUE - 1),
        dbms_lob.INSTR(INVOICE,';',1,INVOICE_SINGLE.COLUMN_VALUE - 1) + 1)
        END) AS INVOICE_INN
    FROM
        INVOICES T,
        TABLE ( CAST(MULTISET(
            SELECT
                LEVEL
            FROM
                DUAL
            CONNECT BY
                dbms_lob.INSTR(INVOICE,';',1,LEVEL) <> 0
        ) AS SYS.ODCINUMBERLIST) ) INVOICE_SINGLE)) TAB 
         WHERE NOT EXISTS (SELECT 1 FROM INVOICE_CATEGORIZED IC
        WHERE IC.INVOICE_NUMBER  = TAB.INVOICE_NUMBER
        AND IC.INVOICE_NAME = TAB.INVOICE_NAME)
    

    db<>fiddle demo

    Cheers!!