Escolar Documentos
Profissional Documentos
Cultura Documentos
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
DBA: XML
Get an overview of SQL and XML interoperability and learn how to begin working with XML documents stored in an Oracle database. Published December 2006 XML data is commonly used in todays production systems and is a major part of database implementations. In the past, this fact caused design problems for database developers who consequently had to store, query, and update XML data as unstructured LOBs, or alternatively, shred data into relational tables and then put it back together. This approach resulted in programming complications and inefciencies because the access mechanisms were immature. The Oracle XML DB feature that was rst delivered with Oracle9i Database Release 2 provided groundbreaking features for storing, retrieving, and manipulating XML data in the database. Oracle 10g Release 2 XML DB, however, greatly extends this initial approach in which XML data is little more than a BLOB in the database. If you are a DBA or a developer new to the implementation of XML in Oracle, this article is for you: you will get an overview of SQL and XML interoperability and learn how to begin working with XML documents stored in an Oracle 10g Release 2 database, and about the many features of Oracle Database 10g Release 2 that DBAs and developers should become comfortable with before beginning to work with XML in the database. Thanks to these SQL/XML features, the skills you've already acquired while working with relational data can easily be enhanced to help you work with XML.
1 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
The XML DB schema and its objects can also be checked to see that Oracle XML DB has been installed.
Lets focus on the structured and unstructured storage for XML data and look at these in more detail. Structured storage. Structured XML storage is implemented as a set of objects. These objects can be implemented in a relational format through tables with referential constraints optionally
2 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
implemented between the tables. They can also be implemented by using an XMLSchema to decompose an XMLType document into a set of objects. In the case where relational tables are used, the tables may be designed in advance for this purpose or, alternatively, existing tables can be used. The document is in effect stored as a virtual document through the relational tables, with its logical structure maintained. This approach maintains Document Object Model (DOM) delity, although it is not a byte-for-byte physical representation of the document. This can be done by creating an XMLType view over existing relational data. Structured storage has some performance advantages over unstructured storage and can be chosen to provide more query and update optimization through the table and index design. XML operations on structured storage can help to reduce memory and storage because XML tags are not stored and because there is potentially a more-granular level of data retrieval and usage. Index usage with b-tree and function-based indexes is enhanced, and in-place updates can be performed on pieces of the document using XPath rewrite. All of this helps performance and is discussed in more detail later in this article. There are also some disadvantages to using structured storage. Inserting and retrieving an entire document can take more overhead. There is also limited exibility, because only documents that match the XMLSchema can be storedalthough there are cases where this is actually an advantage. The document is not stored as a byte-for-byte representation of the original, and the order of data in a document is not maintained. However, no data will be lost. Think of highly structured data as being mostly XML, where each element of the data can be clearly dened. Unstructured storage. XML can be stored in Oracle in an unstructured manner using CLOB storage such that SQL queries will not know the structure of the data. This data can be stored using Oracles XMLType datatype. Unstructured data may be chosen in cases where you want the stored data to match the exact physical representation of the document. Also, if the data is not updated often or if there is a large percentage of inserts or reads of the entire document (rather than pieces of the document), it may be more efcient to keep the data together in one spot. There are also situations where you need to keep documents exible, and in these cases an XMLType table or column can be useful. A disadvantage of unstructured storage is that updates to pieces of a document are generally not as efcient as with structured data. Also, XPath operations that construct DOM from CLOBs using functions can be an expensive use of system resources. Other issues with unstructured data are that SQL constraints cannot be implemented and that memory management is not as efcient. Think of unstructured data as mostly not XML data and where most or all of the data is simply seen as a single CLOB. Now that youve been introduced to the storage models, lets take a look at some naming features.
3 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
Whats in a Namespace?
This is a large topic and one of the more complex XML DB concepts to understand. In this article, we will cover some namespace concepts to give you a gist of what these are and how they are used. A namespace is used to describe a set or collection of related attributes or elements in an XML document. Namespaces can be used to ensure that document constructs have a universally unique name. XMLSchema in particular takes advantage of this feature, as a target namespace is usually the same as the URI of the XMLSchema. Examples of namespaces are shown below. Note that the naming looks similar to an internet URL. This naming standard is recommended by the World Wide Web Consortium (W3C) but is not required. The URI is used to uniquely identify the name of a registered XMLSchema in the database and does not need to be the physical URI where a document is located. XMLType methods and XML functions make use of namespace prexes. When an XML document has no target namespace, then the namespace prex is in the noNameSpace namespace. Attribute xsi:noNamespaceSchemaLocation can be used for the schema URI. If an element does not have another namespace prex, a namespace can be applied by default when it applies to an element where it is declared. There are two special namespaces that you will see regularly. These are http://www.w3.org /2001/XMLSchema, which is the overall XMLSchema namespace, and http://xmlns.oracle.com/xdb, which is the Oracle-supplied XML DB namespace. The latter namespace has functions that get written to underlying SQL functions. Some of the XPath functions are also rewritten. Examples are ora:contains, ceiling, oor, not, string-length, substring, and translate. Attributes used by XML DB also belong to this namespace. When dening an element, we can specify a namespace for that element. In XML, we can dene this as
<elementName xmlns:ab="http.name.com" />
As you see, we gave an elementName, which is the element we are working on (for example, orders). Xmlns is a reserved word and tells us that this is a namespace denition. The ab part is called a prex. This prex is a short name that is bound to the URI. In this case, ab is bound to http.name.com, and ab can be prexed to an element name. Below we will create a very small schema and declare a bind prex xs to http://www.w3.org /2001/XMLSchema and prex xdb to http://xmlns.oracle.com/xdb . In order to declare the namespace, we use xmlns to bind them. Notice that the xs prex is used in this case on the schema element names.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xdb= "http://xmlns.oracle.com/xdb" version="1.0"> <xs:element name="INVOICESCHEMA" xdb:defaultTable="INVOICESCHEMA">
4 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
<xs:complexType> <xs:sequence> <xs:element name="MailAddressTo"> <xs:complexType> <xs:sequence> <xs:element name="Person" type="xs:string"/> <xs:element name="Street" type="xs:string"/> </xs:sequence> <xs:attribute name="id" type="xs:string" use="required"/> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
Weve only touched the surface of namespaces here. Refer to the Oracle XML DB Developers Guide 10g Release 2, on Oracle Technology Network (OTN), for more information on this topic.
Now we can create tables that can contain XMLType data in two ways. The rst will be a table with a column of XMLType. The second will be a table dened as type XMLType. 1. Create a table with an XML column.
create table invoiceXML_col ( inv_id number primary key, inv_doc XMLType);
Each of the above statements implicitly creates two indexes in each tableone for the primary key and one for the LOB.
5 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
Now we will insert an invoice document into both tables. Note that we are using character set AL32UTF8 and will specify this to pass the character set encoding to be used for the le being read. Data will be inserted into both tables to show the similarity between the SQL statements.
Insert into invoicexml_col values (1, XMLType(bfilename('XMLDIR', 'invoicexml.txt'), nls_charset_id('AL32UTF8') )); Insert into invoicexml_tbl values (XMLType(bfilename('XMLDIR', 'invoicexml.txt'), nls_charset_id('AL32UTF8')));
We now have two XML documents loaded into the database using an XMLType table and column. Its as simple as that.
6 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
<xs:element name="City" type="xs:string"/> <xs:element name="State" type="xs:string"/> <xs:element name="Zipcode" type="xs:string"/> </xs:sequence> <xs:attribute name="id" type="xs:string" use="required"/> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
2. Register the above schema in the database using procedure DBMS_XMLSCHEMA.registerSchema. The username you are using to connect to the database will require that the alter session privilege be granted to it so that the schema can be successfully registered.
BEGIN DBMS_XMLSCHEMA.registerSchema( SCHEMAURL => 'http://xmlns.oracle.com/xdb/invoiceformtest.xsd', SCHEMADOC => bfilename('XMLDIR','invoiceformtest.xsd'), CSID => nls_charset_id('AL32UTF8')); END; /
To delete the schema, simply run the DBMS_XMLSCHEMA.deleteSchema statement, as shown below:
BEGIN DBMS_XMLSCHEMA.deleteSchema( SCHEMAURL => 'http://xmlns.oracle.com/xdb/invoiceformtest.xsd', DELETE_OPTION => dbms_xmlschema.DELETE_CASCADE_FORCE); END; /
3. The above statement also creates table invoiceformtest because of the xdb:defaultTable="INVOICEFORMTEST" statement in the schema denition above. Without this, a generated name (one that you would not want to work with) would have been created. 4. Now we are ready to enter documents into the XMLSchema-based table from an XML document that is stored in XML_DIR and is in the format specied by the implemented schema.
Insert into invoiceformtest values (XMLType(bfilename('XMLDIR', 'invoiceformtest.txt'), nls_charset_id(' AL32UTF8')));
Lets look at what weve just created using the object_value pseudocolumn on the XML document.
SQL> select object_value from invoiceformtest; OBJECT_VALUE <INVOICEFORMTEST> <MailAddressTo id="1"> <Person>Joe Smith</Person> <Street>10 Apple Tree Lane</Street> <City>New York</City>
7 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
Were done!
8 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
OBJECT_VALUE <Invoice> <MailAddressTo id="PA"> <Person>Joe Smith</Person> <Street>10 Apple Tree Lane</Street> <City>New York</City> <State>NY</State> <Zipcode>12345</Zipcode> </MailAddressTo> <MailAddressFrom id="PA"> <Person>Ed Jones</Person> <Street>11 Cherry Lane</Street> <City>Newark</City> <State>NJ</State> <Zipcode>67890</Zipcode> </MailAddressFrom> <Details id="2006Sept1to30PA"> <FromTo>Sept 1, 2006 to Sept 30, 2006</FromTo> <Hours>70</Hours> <Rate>30</Rate> <Taxes>210</Taxes> <TotalDue>2310</TotalDue> <InvDate>Oct 1, 2006</InvDate> <Contractor>Ed Jones</Contractor> </Details> </Invoice>
Using extract. Using extract, we can select an individual node and its leaf nodes from the document by combining extract with object_value. In other words, we can look inside an XML document thats been stored as XMLType. This is true whether weve used structured or unstructured data and also whether or not the data is schema-based. Lets extract the MailAddressTo node and its leaf nodes.
select extract(object_value, '/Invoice/MailAddressTo') from invoicexml_tbl; EXTRACT(OBJECT_VALUE,'/INVOICE/MAILADDRESSTO') <MailAddressTo id="PA"><Person>Joe Smith</Person><Street>10 Apple Tree Lane</Street><City>New York</City><State>NY</Stat e><Zipcode>12345</Zipcode></MailAddressTo>
As you can see, the output includes the MailAddressTo portion of the document and is not prettyprinted (formatted). Also, the syntax used to accomplish this is very simple. Whats important is that we were able to look inside the document without dumping the entire thing. Using extractValue. The data value that exists in a leaf node can be extracted using extractValue. A higher - level node such as MailAddressTo cannot be extracted using this function. Note that the output of this is not in XML-syntax format and contains simply the data value.
select extractValue(object_value, '/Invoice/MailAddressTo/Person') Person from invoicexml_tbl; PERSON Joe Smith
Using existsNode. ExistsNode is used in a similar fashion, to search for specic values at the node level (and only the node level) of a document. It returns a True or False ag to specify whether a
9 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
search was successful. The = 1 predicate is not a count but rather represents a True condition, and = 0 is False.
Select count(*) from invoicexml_tbl where existsNode( object_value, '/Invoice/MailAddressTo[Person="Joe Smith"]') = 1; COUNT(*) 1
Using XMLSequence. Unlike extractValue, which can only extract a value from a single node, XMLSequence can be used to look at multiple nodes or a fragment of a document. It does this by creating a virtual table that consists of XMLType objects. Lets compare extractValue with XMLSequence using the MailAddressTo branch node.
select extractValue(object_value, '/Invoice/MailAddressTo') from invoicexml_tbl; from invoicexml_tbl * ERROR at line 2: ORA-19025: EXTRACTVALUE returns value of only one node
This ORA-19025 message is self-explanatory. We can fortunately overcome this by restructuring the query and using XMLSequence, as shown below:
select value(addr) from invoicexml_tbl i, table(XMLSequence( extract(i.object_value, '/Invoice/MailAddressTo'))) addr where existsNode(i.object_value, '/Invoice/Details[@id="2006Sept1to30PA"]') = 1; VALUE(ADDR) <MailAddressTo id="PA"><Person>Joe Smith</Person><Street>10 Apple Tree Lane</Street><City>New York</City><State>NY</Stat e><Zipcode>12345</Zipcode></MailAddressTo>
Because XMLSequence creates a virtual table, we can also use this function on a leaf node.
select value(person) from invoicexml_tbl i, table(XMLSequence( extract(i.object_value, '/Invoice/MailAddressTo/Person'))) person where existsnode(i.object_value, '/Invoice/Details[@id="2006Sept1to30PA"]') = 1; VALUE(PERSON) <Person>Joe Smith</Person>
FLWOR. FOR, LET, WHERE, ORDER BY, and RETURN (FLWOR; pronounced ower) is one of the most important and powerful expressions in XQuery syntax. Either FOR or LET must exist, WHERE and ORDER BY are optional, and RETURN is mandatory.FLWOR on its own is a large topic to cover. This section gives you an introduction to the power of this statement. FOR binds one or more variables in an iterative manner, in the order that the variables are listed. Values listed previously can then be used in a subsequent set of values. This also works similarly to a
10 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
SQL From clause. Values listed previously can then be used in a subsequent set of values, as shown below:
For $var in (1,2,3) , $varPlus5 in (5+$var, 5+$var, 5+$var)
The three iterations set $var and $varPlus5 to 1,6; 2,7; and 3,8, respectively. LET, like FOR, binds variables iteratively, and values can be computed using previously calculated values. As with FOR, LET can be thought of as a SQL FROM clause. LET can also be used to perform joins. WHERE lters data in the same manner as a SQL WHERE clause. ORDER BY optionally sorts the data. RETURN returns the nal result set from the ltered and ordered FLWOR expression. FLWOR being used with XMLQuery(). Lets look at an example where we query and join two documents: partys.xml to an orders.xml document on the Party key. This XML data is in the Oracle XML DB Repository. To do this, we will use XMLQuery(); FLWOR; and XQuery functions doc, count, avg, and integer. These are in the namespace for built-in XQuery functions, http://www.w3.org/2003/11/xpath_functions. The query below reads as follows: Using function fn:doc, FOR all partyno attributes in partys.xml, join (LET) all order elements in orders.xml that match on partyno (variable $p was bound in the FOR statement). This produces a stream of items ($p and $o), with $p representing a party number and $o a set of orders for that party. Get the items WHERE there is more than 1 order. ORDER BY the average amt descending using XQuery function avg in namespace fn. Amt is attached to order element $o. Return the party number (bound to $p) and child element ordercount.
SELECT XMLQuery()('for $p in fn:doc("/public/partys.xml")/partys/party/@partyno let $o := fn:doc("/public/orders.xml")/orders/order[@partyno = $p] where fn:count($o) > 1 order by fn:avg($o/@amt) descending return <big-party>{$p, <ordercount>{fn:count($o)}</ordercount>, <avgamt>{xs:integer(fn:avg($o/@amt))}</avgamt>} </big-party>' RETURNING CONTENT) ORDERS FROM DUAL; ORDERS <big-party>1111<ordercount>2</ordercount><avgamt>3500</avgamt></big-party>
Yes, this query is doing a lot and shows some of whats possible when using FLWOR expressions on XML documents.
11 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
implemented in the http://xmlns.oracle.com/xdb namespace, which uses the prex ora:. Along with these are two other XPath functions. These are not yet part of the SQL/XML standard but are expected to be in the future. The ora:view function is a particularly valuable one that can be used to transform relational data into XML format. All of these are described below. ora:view XQuery function. This is a valuable function to create a view over relational tables. This can make them appear as if they are XML documents.
Syntax: ora:view ([db-schema STRING, ] db_table STRING) RETURNS document-node (element())
Examples that use ora:view are shown later in the article. ora:contains XQuery function. The namespace prex ora: and name contains are used together to create an XPath function that can be used as an XPath argument to the SQL/XML existsNode, extract, and extractValue functions.This allows you to perform a structural search with a text predicate. This function returns a positive number if text_query matches the input_text. If they do not match, then 0 is returned. When they are used with existsNode, extract, or extractValue, you need to include the namespace mapping parameter xmlns:ora="http://xmlns.oracle.com/xdb". The syntax for ora:contains is shown below. The owner is the current user in cases where a policy_owner is not dened. The policy_name is the name of the matching rules that will be applied. The default matching rules are dened by ctxsys.default_policy_oracontains.
Syntax: ora:contains (input_text, text_query [, policy_name] [, policy_owner])
The example below shows how we can use ora:contains as an argument to existsNode.
SELECT count(*) FROM invoicexml_tbl WHERE existsNode(object_value, '/Invoice/MailAddressTo/Person [ora:contains(text(), "Joe Smith") > 0]', 'xmlns:ora="http://xmlns.oracle.com/xdb"') = 1; COUNT(*) 1
ora:matches XQuery function. This function uses regular expressions to match text. This is similar to the SQL REGEXP_LIKE condition except that it uses XQuery arguments instead of SQL datatypes. True is returned if the target_string matches the regular expression match_pattern ; if not, False is returned. As you can see in the syntax below, match_parameter can be added to specify additional criteria to use in a search. An example of this is to provide case sensitivity.
Syntax: ora:matches (target_string, match_pattern [, match_parameter])
ora:replace XQuery function. This extends the ora:matches function by replacing the target_string with the replace_string if the match_pattern is met ( True ). As with ora:matches, this uses regular expressions to match the text.
Syntax: ora:replace (target_string, match_pattern,
12 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
replace_string [, match_parameter])
ora:sqrt XQuery function. As you may expect from the name, this returns the square root value of the provided number.
Syntax: ora:sqrt (number)
XPath extension functions: ora:instanceof and ora:instanceof-only. Oracle XML DB can support schema-based data when the datatypes of attributes and elements are known. Because XPath 1.0 is not aware of datatype information, there are XML DB extension functions in namespace http://xmlns.oracle.com/xdb that allow you to restrict an XML document node to a specic datatype. Function ora:instanceof can be used to restrict a node to a datatype or subtype, and ora:instanceof-only restricts a node to the datatype only. A subtype is a feature than can be used to extend or restrict a type.
Syntax: ora:instanceof(nodeset-expr, typename [, schema-url]) Syntax: ora:instanceof-only(nodeset-expr, typename [, schema-url])
In the above syntax, nodeset-expr is usually a relative XPath expression. This function returns True if the datatype of any node matches typename and False if it does not. Typename can be qualied with a namespace prex. T hese functions will return False for non-schema-based data because it does not have a datatype associated with elements and attributes .
Querying XML Data in the XML DB Repository Using fn:doc and fn:collection Functions
There are two important XQuery functions that can be used to query all of the resources in the XML DB Repository. Fn:doc is an XQuery function that can obtain a repository le containing XML data. This le resource is pointed at by its URI argument. XQuery variables can be bound to data using the FLWOR expressions FOR and LET. XQuery function fn:doc can be used to read a single XML document stored in the XML DB repository. The second XQuery function that queries resources in the repository is fn:collection. This can return a number of similar documents stored in the same folder in the repository. Lets create repository resources to illustrate how fn:doc and fn:collection work with some simple examples. We will start by creating a resource using the DBMS_XDB PL/SQL package. This can be used to manage resources in XML DB. The createResource procedure is used in this case to create new le resources that contain the Orders and Partys XML documents. Create the orders and partys resource names used in the examples below. There is one additional resource created named ordersnamespace.xml, which shows an example of a namespace being used.
DECLARE res BOOLEAN;
13 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
ordersxmlstring VARCHAR2(500):= '<?xml version="1.0"?> <orders> <order orderno="15" partyno="1111" itemname="Widget" amt="5000"/> <order orderno="25" partyno="1111" itemname="Do dad" amt="2000"/> <order orderno="35" partyno="2222" itemname="All purpose item" amt="7000"/> <order orderno="45" partyno="3333" itemname="The best thing" amt="15000"/> </orders>'; partysxmlstring VARCHAR2(500):= '<?xml version="1.0"?> <partys> <party partyno="1111" partyname="ABC Corp" partycity="Toronto"/> <party partyno="2222" partyname="Freds Inc" partycity="Chicago"/> <party partyno="3333" partyname="Gofaster Corp" partycity="Montreal"/> </partys>'; ordersxmlnsstring VARCHAR2(500):= '<?xml version="1.0"?> <orders xmlns="http://order.com"> <order orderno="15" partyno="1111" itemname="Widget" amt="5000"/> <order orderno="25" partyno="1111" itemname="Do dad" amt="2000"/> <order orderno="35" partyno="2222" itemname="All purpose item" amt="7000"/> <order orderno="45" partyno="3333" itemname="The best thing" amt="15000"/> </orders>'; BEGIN res := DBMS_XDB.createResource('/public/orders.xml', ordersxmlstring); res := DBMS_XDB.createResource('/public/partys.xml', partysxmlstring); res := DBMS_XDB.createResource('/public/ordersnamespace.xml', ordersxmlnsstring); END;
We can see the resources we just created by querying the resource_view, as shown below:
SQL> select any_path, res from resource_view where any_path like '%partys%'; ANY_PATH RES /public/partys.xml <Resource xmlns="http://xmlns.oracle.com/xdb/XDBResource.xsd"> <CreationDate>2006-06-19T17:12:00.414000</CreationDate> <ModificationDate>2006-06-19T17:12:00.414000</ModificationDate> <DisplayName>partys.xml</DisplayName> <Language>en-US</Language> <CharacterSet>WINDOWS-1252</CharacterSet> <ContentType>text/xml</ContentType> <RefCount>1</RefCount> </Resource>
14 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
Fn:collection can be used a little differently than fn:doc by returning all of the documents stored in the same folder in the repository. The output produced from this statement was not pretty-printed, and the formatting below was done manually to make the document more readable.
SELECT XMLQuery('for $p in fn:collection("/public") return $p' RETURNING CONTENT) collection_public FROM DUAL; COLLECTION_PUBLIC ---------------------------------------------------------------------<orders> <order orderno="15" partyno="1111" itemname="Widget" amt="5000"/> <order orderno="25" partyno="1111" itemname="Do dad" amt="2000"/> <order orderno="35" partyno="2222" itemname="All purpose item" amt="7000"/> <order orderno="45" partyno="3333" itemname="The best thing" amt="15000"/> </orders> <orders xmlns="http://order.com"> <order orderno="15" partyno="1111" <order orderno="25" partyno="1111" <order orderno="35" partyno="2222" <order orderno="45" partyno="3333" </orders> itemname="Widget" amt="5000"/> itemname="Do dad" amt="2000"/> itemname="All purpose item" amt="7000"/> itemname="The best thing" amt="15000"/>
<partys> <party partyno="1111" partyname="ABC Corp" partycity="Toronto"/> <party partyno="2222" partyname="Freds Inc" partycity="Chicago"/> <party partyno="3333" partyname="Gofaster Corp" partycity="Montreal"/> </partys>
There are many other DBMS_XDB procedures and functions that can be used to manage all XML DB resources, such as providing the ability to delete resources and create folders. These can be found in the Oracle XML DB Developers Guide 10g Release 2, on OTN.
15 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
evaluated. The function returns the result of the XQuery expression as an XMLType instance. The XMLQuery() function can also take in SQL expressions as arguments, where the values are bound to XQuery variables when the expression is evaluated. The results are returned as an XMLType instance. Lets look at two examples where we use XMLQuery() on relational and XML data. Example combining XMLQuery() with ora:view and FLWOR expressions. In the rst example, we will use XMLQuery() on physical relational tables. XMLQuery() must act on XML data, and this is accomplished using the ora:view feature on relational tables Employee and Department in the HR schema. Once ora:view is used on both relational tables, they appear as XML and we are able to then use XQuery expressions, including a nested FLWOR expression. The query below is doing the following: For each department, get the department id, and for all employees that match the department id with a commission greater than 30 percent, return the employee rst and last name. Note that the FOR expression is used twice in this query.
SELECT XMLQuery( 'FOR $dep in ora:view("DEPARTMENTS")/ROW RETURN <Department id="{$dep/DEPARTMENT_ID}"> <Employee> {FOR $emp in ora:view("EMPLOYEES")/ROW WHERE $emp/DEPARTMENT_ID eq $dep/DEPARTMENT_ID and $emp/COMMISSION_PCT > .3 RETURN ($emp/FIRST_NAME, $emp/LAST_NAME)} </Employee> </Department>' RETURNING CONTENT) HIGH_COMMISSION_EMP_NAMES FROM DUAL; HIGH_COMMISSION_EMP_NAMES --------------------------------------------------------------<Department id="10"><Employee></Employee></Department><Department id="20"><Employee></Employee></Department><Department id="30"><Employee></Employee></Department><Department id="40"><Employee></Employee></Department><Department id="50"><Employee></Employee></Department><Department id="60"><Employee></Employee></Department>
The result, as you can see, is not pretty-printed. The query syntax is slightly complex but shows that we have the ability to transform relational data into XML data with ora:view and that we can perform a join operation on XML documents and apply predicates on the data inside the documents. Example using XMLQuery() with an XMLType column and FLWOR expressions. Table invoicexml_col, which we created above and into which we inserted a document, contains an XMLType column inv_doc. The Invoice data that is stored in this column is in XML format. In this query, we will pass XMLType column inv_doc to XQuery using the XMLQuery() function with the PASSING clause. Notice how we can return some specic elds from the Invoice document based on WHERE predicates. In effect, we are able to get inside the XML document and retrieve specic elds based on predicates rather than only being able to see this document as a CLOB. The SELECT statement below applies to all of the rows of invoicexml_col. We then iterate across all
16 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
the invoice rows with the FOR statement. The WHERE predicate picks out the elements from Zipcode 12345, and we then RETURN the City, State, and Zipcode and whether the City and State are entered correctly for this Zipcode. An IFTHENELSE construct shows some additional power to this syntax.
Select XMLQuery( 'FOR $i in /Invoice WHERE $i/MailAddressTo/Zipcode = 12345 RETURN <Details> <Zipcode num="{$i/MailAddressTo/Zipcode}"/> <CityName char="{$i/MailAddressTo/City}"/> <City>{IF ($i/MailAddressTo/City = "New York") THEN "Correct City" ELSE "Incorrect City"} </City> <State>{if ($i/MailAddressTo/State = "NY") then "Correct State" else "Incorrect State"} </State> </Details>' PASSING inv_doc RETURNING CONTENT) ny_invoice FROM invoicexml_col; NY_INVOICE <Details><Zipcode num="12345"></Zipcode> <CityName char="New York"></CityName> <City>Correct City</City> <State>Correct State</State> </Details>
Both queries illustrate the power we have to look inside and process XML documents in a detailed and piece-wise manner. The functionality provided is similar to what weve been able to do with relational dataimpressive! XMLTable() function. This function enables an XML value to be interpreted as a table or a set. Its used to return a table and columns from the evaluation of XQuery expressions, rather than returning a sequence as XQuery would normally do. XMLType data can be queried and the XML results split or shredded into relational formatthink of this as creating a virtual table. The virtual table can then be used to insert data into other tables or can be queried. Relational views can also be constructed over XML data. The XMLTable() function can also be used in a SQL From clause. Example using XMLTable() with the COLUMNS clause. We will use our invoicexml_col table, introduced earlier, to illustrate how XMLTable() can be used to transform XML data into relational format. In the example below, XMLTable() accesses the Invoice document that is stored in column inv_doc. The paths of the data elements we want are mapped to new column names and formats using the COLUMNS clause.The XMLTable() function returns the data as a virtual table, and the result of this query is the same as if we had queried a relational table. Note the use of the WHERE clause at the bottom of the query that allows us to lter XML data in the exact same way we would with any SQL query written for relational data. The query and output are shown below:
SELECT inv_id, a.PersonName, a.StreetName, a.CityName, a.State, a.Zipcode
17 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
FROM invoicexml_col, XMLTABLE('/Invoice' PASSING invoicexml_col.inv_doc COLUMNS PersonName varchar2(10) PATH '/Invoice/MailAddressTo/Person', StreetName varchar2(20) PATH '/Invoice/MailAddressTo/Street', CityName varchar2(10) PATH '/Invoice/MailAddressTo/City', State varchar2(5) PATH '/Invoice/MailAddressTo/State', Zipcode varchar2(7) PATH '/Invoice/MailAddressTo/Zipcode' ) a WHERE a.CityName like 'New%'; INV_ID 1 PERSONNAME Joe Smith STREETNAME 10 Apple Tree Lane CITYNAME STATE New York ZIPCODE NY 12345
18 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
return $dep' RETURNING CONTENT) AS high_commission_employees FROM DUAL; QUERY_PLAN SELECT STATEMENT SORT HASH JOIN TABLE ACCESS TABLE ACCESS FAST DUAL OBJECT_NAME 2 EMPLOYEES DEPARTMENTS 5 2 2 2 COST BYTES LEVEL 1 82 2 328 3 104 4 1512 4 2
As you can see, the access path that the optimizer chose does not use indexes. Because ora:view allows us to return results from a relational query as XML elements, we can simply create b-tree indexes on the relational tables and see if this can improve performance.
Create index emp_idx1 on employees (department_id, commission_pct); Create index dept_idx1 on departments (department_id); QUERY_PLAN SELECT STATEMENT SORT TABLE ACCESS NESTED LOOPS INDEX INDEX FAST DUAL OBJECT_NAME DEPARTMENTS EMP_IDX1 DEPT_IDX1 COST 2 1 2 1 0 2 82 56 328 104 BYTES LEVEL 1 2 3 4 5 5 2
The indexes are now used, and cost decreased very slightly. Our tuning of this XQuery expression using ora:view is very similar to our tuning of standard, non-XML SQL. As with standard SQL, rewriting the query and also using features such as bind variables rather than hard-coded string values can help improve performance. Optimizing structured XMLType data. XPath rewrite can optimize structured (object-relational) storage techniques. The optimizer can make one other internal performance improvement: It can change XPath-based functions into relational statements when the following are true: The XMLType data uses a registered XMLSchema. This is another advantage of using schema-based data. Attributes map to underlying SQL (relational) tables. Structured storage is used. This provides the possibility of query rewrite for performance reasons. It also allows relational performance tuning techniques to be used, as shown above. Now, lets optimize a query on structured, nonrelational XMLType data. We will start with a very simple example using the invoicexml_tbl table created earlier.
explain plan for select extract(object_value, '/Invoice/MailAddressTo') from invoicexml_tbl where extractValue(object_value, '/Invoice/MailAddressTo/Person')= 'Joe Smith';
19 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
The access path is shown below. QUERY_PLAN SELECT STATEMENT TABLE ACCESS OBJECT_NAME INVOICEXML_TBL COST 3 3 BYTES 87 87 LEVEL 1 2
A function-based index on the predicate used in this query can be created. The index must use the exact same syntax as the query that will use it. This index will be created and the SQL explained one more time to see if the new index is used.
Create index invoicexml_tbl_idx1 on invoicexml_tbl (extractValue(object_value, '/Invoice/MailAddressTo/Person')); QUERY_PLAN SELECT STATEMENT TABLE ACCESS INDEX OBJECT_NAME INVOICEXML_TBL INVOICEXML_TBL_IDX1 COST 1 1 1 BYTES 87 87 LEVEL 1 2 3
The new function-based index is used, and the cost of the query has decreased as a result. Optimizing unstructured XMLType data. Well now perform the exact same test with unstructured XMLType data. Table invtest_unstruct will be created in exactly the same manner as we created invoicexml_tbl, except that we will add the XMLType store as CLOB syntax to ensure that this is dened as unstructured data. The data denition language (DDL), insert, and explain plan are below :
create table invtest_unstruct of XMLtype XMLType store as CLOB; Insert into invtest_unstruct values ( XMLType(bfilename('XMLDIR', 'invoicexml.txt'), nls_charset_id('WE8MSWIN1252') )); explain plan for select extract(object_value, '/Invoice/MailAddressTo') from invtest_unstruct where extractValue(object_value, '/Invoice/MailAddressTo/Person')='Joe Smith' / QUERY_PLAN SELECT STATEMENT TABLE ACCESS OBJECT_NAME INVTEST_UNSTRUCT COST 2 2 BYTES LEVEL 2002 2002 1 2
We will now create a function-based index to see if it will be used and if the expected cost has decreased. Note that the create index syntax is the same as the syntax used in the query predicate.
Create index invtest_unstruct_idx1 on invtest_unstruct (extractValue(object_value, '/Invoice/MailAddressTo/Person')); QUERY_PLAN SELECT STATEMENT TABLE ACCESS INDEX OBJECT_NAME INVTEST_UNSTRUCT INVTEST_UNSTRUCT_IDX1 COST 1 1 1 BYTES 2002 2002 LEVEL 1 2 3
20 de 21
27-04-10 11:54
http://www.oracle.com/technology/pub/articles/quinlan-xml.htm...
As you can see, the same index and query can be used effectively with structured and unstructured data. In general, however, note that structured data access is generally more efcient than unstructured access.
Conclusion
Oracle Database has evolved to incorporate XML standards and data at a rapid pace. Oracle9i Database introduced the XML DB repository and a new datatype, XMLType, which delivered both LOB and structured storage options. Oracle XML DB features provide the ability to perform native XML processing in the database through a hierarchical model that maps URIs to database objects. XPath expressions are used to operate on individual elements of a document through a logical tree using the concepts of a node and path. XMLSchema support was also included with Oracle9i Database. Oracle Database 10g enhanced XML support with the W3C XML XQuery language, which includes the XMLQuery() and XMLTable() functions. The combination of these features facilitates the interchangeable use of relational data and XML data in Oracle Database 10g Release 2. As this article demonstrates, SQL queries can operate on XML data, and XML queries are now able to access relational data. A key to this is Oracles SQL/XML implementation of the XMLQuery() and XMLTable() functions. Oracles standards-based approach also supports popular protocols such as FTP, HTTP, and WebDAV to allow common client tools and applications to access, edit, and publish XML data stored in the database. In this article you've learned that the skills youve already acquired while working with relational data can easily be enhanced to allow you to work with XML using these SQL/XML features. An important example of this is our ability to enhance performance of XML data access through Oracles indexing, explain, and storage features. Its critical that designers, developers, and DBAs keep up-to-date with this quickly changing technology. Tim Quinlan [tquinlan@tlqconsulting.com] is an Oracle certied Database Administrator with experience in Oracle 7 thru Oracle10g Release 2. He has worked with Databases since 1981, performing the roles of DBA, architect, designer and implementer of enterprise-wide Data Warehouse and transactional Databases. Tim has spoken at many conferences, taught database courses, and written feature articles for leading database publications. His main (professional) interest is designing and implementing very large, high-performance, high-availability database systems.
21 de 21
27-04-10 11:54