{"id":73129,"date":"2016-03-02T10:39:11","date_gmt":"2016-03-02T10:39:11","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/uncategorized\/xquery-for-absolute-beginners-part-2-xquery-and-the-oracle-database\/"},"modified":"2021-07-14T13:07:13","modified_gmt":"2021-07-14T13:07:13","slug":"xquery-for-absolute-beginners-part-2-xquery-and-the-oracle-database","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/oracle-databases\/xquery-for-absolute-beginners-part-2-xquery-and-the-oracle-database\/","title":{"rendered":"XQuery for Absolute Beginners: Part 2 \u2013 XQuery and the Oracle Database"},"content":{"rendered":"<p>In this series of articles I&#8217;m hoping to provide a primer for newish Oracle developers who are curious about XQuery and are looking to dip their toes into its world. If that&#8217;s you, hi, nice to meetcha.<\/p>\n<p>Or rather, nice to meetcha again. This is the second article in the series; go back and <a href=\"https:\/\/allthingsoracle.com\/xquery-for-absolute-beginners-part-1-xpath\/\">read the first<\/a> if you haven&#8217;t yet.<\/p>\n<p>In this article we&#8217;re going to talk about Oracle&#8217;s implementation of the SQL\/XML functions that include XQuery &#8211; or, in other words, how to use XQuery in your Oracle database. (SQL\/XML, in case you were wondering, is that part of the SQL standard that instructs the various relational databases on how to deal with XML and ensures that the skills you learn in this article are mostly transferable between RDBMS platforms. Oh, you <em>weren&#8217;t<\/em> wondering? Never mind then.)<\/p>\n<h5>Sample Data<\/h5>\n<p>To really get our teeth into this, we need to create a table and load it with some sample data. Our table will need to have a column of the XMLTYPE type, which is Oracle&#8217;s native XML datatype.<\/p>\n<pre>CREATE TABLE sitcoms\r\n(\r\n  id      NUMBER,\r\n  sitcom  VARCHAR2(30),\r\n  data    XMLTYPE\r\n);\r\n<\/pre>\n<p>Now we&#8217;ve got our table, let&#8217;s stuff in some data. We&#8217;ll use our XML from the first article and one other.<\/p>\n<pre>INSERT INTO sitcoms (id, sitcom, data)\r\nVALUES (1, 'Friends', xmltype ('&lt;friends&gt;\r\n  &lt;characters&gt;\r\n  &lt;character status=\"Lead\" actorid=\"001\"&gt;\r\n  &lt;firstname&gt;Ross&lt;\/firstname&gt;\r\n  &lt;lastname&gt;Geller&lt;\/lastname&gt;\r\n  &lt;gender&gt;Male&lt;\/gender&gt;\r\n  &lt;birthdate&gt;1967-10-18&lt;\/birthdate&gt;\r\n  &lt;occupation&gt;Palaeontologist&lt;\/occupation&gt;\r\n  &lt;\/character&gt;\r\n  &lt;\/friends&gt;')\r\n);\r\n\r\nINSERT INTO sitcoms (id, sitcom, data)\r\nVALUES (2, 'Episodes', xmltype ('&lt;episodes&gt;\r\n  &lt;characters&gt;\r\n  &lt;character status=\"Lead\" actorid=\"003\"&gt;\r\n  &lt;firstname&gt;Matt&lt;\/firstname&gt;\r\n  &lt;lastname&gt;LeBlanc&lt;\/lastname&gt;\r\n  &lt;gender&gt;Male&lt;\/gender&gt;\r\n  &lt;birthdate&gt;1967-07-25&lt;\/birthdate&gt;\r\n  &lt;occupation&gt;Actor&lt;\/occupation&gt;\r\n  &lt;\/character&gt;\r\n  &lt;\/episodes&gt;')\r\n);\r\n<\/pre>\n<p><a href=\"http:\/\/www.readfree.ly\/wp-content\/uploads\/2016\/02\/xquery_example.txt\" target=\"_blank\">Download the complete script<\/a><\/p>\n<h5>SQL\/XML<\/h5>\n<p>I know I&#8217;m beginning to get a little boring with this SQL\/XML thing, but it&#8217;s probable useful at this point to bring it up again. There&#8217;s a huge amount that you can do with XML in the Oracle database. The corporation has pretty much fully implemented everything in the SQL\/XML standard \u2013 and thrown in a few native functions too.<\/p>\n<p>However, this article is about XQuery, and so we&#8217;ll be restricting ourselves to the 3 main SQL\/XML functions that use XQuery: XMLQuery, XMLTable and XMLExists.<\/p>\n<p>Here&#8217;s a quick rule of thumb: you use XMLQuery in the SELECT clause; you use XMLTable in your FROM clause; and you use XMLExists in your WHERE clause.<\/p>\n<h5>XMLQuery<\/h5>\n<p>XMLQuery, as I&#8217;ve just said, lives in the SELECT clause and is a function for querying XML\u00a0data. (You may have heard of other SELECT-centric functions like XMLAgg and XMLElement. They&#8217;re not XQuery functions and \u2013 here&#8217;s another rule of thumb for you \u2013 they&#8217;re mostly used for <em>generating<\/em> XML; XQuery is used for <em>querying<\/em> XML.) XMLQuery queries XML\u00a0data and returns XML.<\/p>\n<p>Here&#8217;s the syntax for XMLQuery<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2016\/03\/xmlquery.jpg\" alt=\"XML Query structure\" \/><\/p>\n<p class=\"caption\">Fig 1 &#8211; XMLQuery syntax<\/p>\n<pre>XMLQuery (\r\n          '&lt;xquery string&gt;'\r\n          PASSING &lt;xmltype column&gt;\r\n          RETURNING CONTENT\r\n          NULL ON EMPTY\r\n        )\r\n<\/pre>\n<p>Basically, you feed it a full XQuery expression as a string and, using the PASSING clause, you set a context &#8211; i.e. tell it where to get the xml you wish to query. Finally, the RETURNING CONTENT is mandatory. (<em>NULL ON EMPTY<\/em> is an optional appendage and, as you&#8217;ve probably guessed, it tells Oracle what to do if your XQuery expression resolves to nothing.)<\/p>\n<p>Here&#8217;s an example. Say we wanted to find out the first names of all the lead characters of our sitcoms, we might run something along these lines:<\/p>\n<pre>SELECT sitcom, \r\n            XMLQUERY('\/\/characters\/character[@status=\"Lead\"]\/firstname' \r\n                      PASSING data \r\n                      RETURNING CONTENT\r\n                    )  character_name\r\nFROM sitcoms;\r\n<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2016\/03\/xmlquery-results.jpg\" alt=\"XML query results\" \/><\/p>\n<h5>XMLTable<\/h5>\n<p>The XMLTable function is usually found hanging around in the FROM clause of queries. It is used to transform the results of an XQuery expression into a virtual table, complete with rows and columns.<\/p>\n<p>Its usefulness is probably immediately obvious to you; once it turns the XML\u00a0into a virtual table it makes it a doddle for you to run your everyday SQL\u00a0statements against it.<\/p>\n<p>Here&#8217;s the syntax:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2016\/03\/xmltable.jpg\" alt=\"XMLTable Syntax\" \/><\/p>\n<p class=\"caption\">Fig 2 &#8211; XMLTable syntax<\/p>\n<pre>XMLTable (\r\n          '&lt;xquery string&gt;'\r\n          PASSING &lt;xml col&gt;\r\n          COLUMNS &lt;col name&gt; &lt;col type&gt; PATH &lt;XQuery path&gt; \r\n        )\r\n<\/pre>\n<p>Basically, you feed it a full XQuery expression as a string along with (in the PASSING clause) the xmltype column that gives it its context. You then (optionally) define the columns of the virtual table you&#8217;d like it to create. (If you don&#8217;t define your columns, XMLTable will create one xmltype column named COLUMN_VALUE. You probably don&#8217;t want \u00a0that, so you really should define your columns.) Finally, the PATH tells XMLTable what portion of the XQuery&#8217;s result should make up the column.<\/p>\n<p>It&#8217;s pretty straightforward, but just in case I haven&#8217;t explained it very well, here&#8217;s an example for you.<\/p>\n<p>Let&#8217;s return to the example we used when we were discussing XMLQuery; say we wanted to find out the details of the lead characters in our sitcoms.<\/p>\n<pre>SELECT sitcoms.sitcom, t.*\r\nFROM sitcoms, XMLTABLE('\/\/characters\/character[@status=\"Lead\"]' \r\n                       PASSING sitcoms.data \r\n                       COLUMNS firstname VARCHAR2(30) PATH 'firstname', \r\n                               lastname VARCHAR2(30) PATH 'lastname',\r\n                               gender   VARCHAR2(10) PATH 'gender'\r\n                      ) t;\r\n<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2016\/03\/xmltable-results.jpg\" alt=\"XMLTable results\" \/><\/p>\n<p>Notice how the resultset is neat and orderly, like a regiment of soldiers standing to attention, rather than a jumble of xml.<\/p>\n<p>I&#8217;d also like to you to notice that, in the FROM clause, I called the\u00a0<em>sitcoms<\/em> table right before I made the call to XMLTable. Without this, it would&#8217;ve failed. You need to make a call to the table with your XML\u00a0right before you call XMLTable.<\/p>\n<p>Notice also that the PATH subclause references the node within the XQuery expression that you want the column to be built from.<\/p>\n<h5>XMLExists<\/h5>\n<p>The XMLExists function returns a boolean that reports if an XQuery expression returns a non-empty sequence, and can be found in the WHERE clause of queries. Well, can\u00a0<em>mostly<\/em> be found in WHERE clauses; the one exception is that you can use XMLExists in case statements in your SELECT clause. But let&#8217;s put that to one side for now; we can talk about it later.<\/p>\n<p>Here&#8217;s the syntax.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/www.readfree.ly\/wp-content\/uploads\/2016\/03\/xmlexists.jpg\" alt=\"XMLExists Syntax\" \/><\/p>\n<p class=\"caption\">Fig 3 &#8211; XMLExists syntax<\/p>\n<pre>XMLExists (\r\n           '&lt;xquery string&gt;'\r\n           PASSING '&lt;xml col&gt;'\r\n          ) \r\n<\/pre>\n<p>Basically, you feed it a full XQuery expression as a string along with (in the PASSING clause) the xmltype column that gives it its context, and if that XQuery expression leads it to an actual snatch of xml it&#8217;ll return TRUE, otherwise it&#8217;ll return FALSE.<\/p>\n<p>Let&#8217;s\u00a0think of an example. We know Matt Leblanc is an actor, but what if we&#8217;re looking for that sitcom where he plays himself rather than a character (in other words, a sitcom where Matt Leblanc is a character, not just a cast member).<\/p>\n<pre>SELECT sitcom\r\n  FROM sitcoms\r\n WHERE XMLEXISTS('\/\/characters\/character[firstname = \"Matt\" and lastname= \"LeBlanc\"]'\r\n                 PASSING data\r\n                );\r\n<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2016\/03\/xmlexists-result.jpg\" alt=\"XMLExists Results\" \/><\/p>\n<p>Ah, that&#8217;s it <em>Episodes<\/em>, the sitcom in which Matt LeBlanc plays himself, and not <em>Friends<\/em> where he plays the character Joey Tribiani.<\/p>\n<p>You know I said that XMLExists can be used in case statements; I should&#8217;ve also mentioned that it can also be used in function-based indexes. It&#8217;s pretty straightforward, but I won&#8217;t go into it as it&#8217;s a little beyond the scope of this article.<\/p>\n<h5>Conclusion<\/h5>\n<p>And that&#8217;s it for this second article in our series on XQuery and Oracle. \u00a0There is a certain elegance and symmetry to the SQL\/XML functions that we&#8217;ve been talking about that I personally find quite attractive. \u00a0I hope that&#8217;s come across in this article.<\/p>\n<p>We don&#8217;t often look for beauty in computer code; but if it&#8217;s prettiness you&#8217;re after, wait for the next article in this series &#8211; it&#8217;s about FLWOR.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this series of articles I&#8217;m hoping to provide a primer for newish Oracle developers who are curious about XQuery and are looking to dip their toes into its world. If that&#8217;s you, hi, nice to meetcha. Or rather, nice to meetcha again. This is the second article in the series; go back and read the first if you haven&#8217;t&hellip;<\/p>\n","protected":false},"author":221907,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143533],"tags":[4459,4217,48540,48541,48542,4734],"coauthors":[],"class_list":["post-73129","post","type-post","status-publish","format-standard","hentry","category-oracle-databases","tag-oracle","tag-xml","tag-xmlexists","tag-xmlquery","tag-xmltable","tag-xquery"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73129","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221907"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=73129"}],"version-history":[{"count":1,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73129\/revisions"}],"predecessor-version":[{"id":91626,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73129\/revisions\/91626"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=73129"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=73129"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=73129"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=73129"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}