Search code examples
oracle-databasematerialized-viewsxmltypeextract-value

Oracle: how to create a fast refresh materialized view that extracts data from XMLType?


I have a table xml_documents with two columns: a document_id column (primary key) and an xml column with some XML data, which is a schema-less XMLType. I can create a materialized view with just the document_id with:

create materialized view mv refresh fast on commit as 
select document_id
from xml_documents

This works fine, but isn't very useful. As you might expect, I'd like the materialized view to extract data from the XML, and for this I use extractValue(). I am trying the following:

create materialized view mv refresh fast on commit as 
select document_id, extractValue(xml, '/my/gaga') gaga
from xml_documents

This fails with:

ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view

How should I go about to create a fast refresh on commit materialized view that extract values from XML?


Solution

  • Your XMLType is (probably) stored as a CLOB. Find the hidden column with a query like this:

    select * from user_tab_cols where table_name = 'XML_DOCUMENTS';
    

    Then create a function to convert a CLOB into an XMLType, and extract the value. Note that the "deterministic" keyword is necessary, although I'm not sure why. Passing data back and forth between SQL and PL/SQL will be slow, but if you're using a materialized view things are probably already slow.

    create or replace function extract_from_clob(p_xml in clob) return varchar2 deterministic
      is
    begin
        return XMLType(p_xml).extract('/my/gaga/text()').getStringVal();
    end;
    /
    

    Then drop and create your materialized view with the system column passed into the function:

    create materialized view mv refresh fast on commit as 
    select document_id, extract_from_clob(SYS_NC00003$) gaga
    from xml_documents;
    

    I'm unsure about using a system-generated hidden column. It works, but doesn't seem like a really good idea. At the very least it will make it difficult to create the object on different systems - you'll need to find the new column name each time.

    It seems weird that XMLTypes don't work when LOBs work fine. I can't find any documentation about this; I'm not sure if it's a bug, an unimplemented feature, or if there's some magic setting that will make it work. If no one else can provide a better answer, it might be worth checking with Oracle support before you use the above approach.