{"id":73162,"date":"2015-06-16T11:31:35","date_gmt":"2015-06-16T11:31:35","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/uncategorized\/anatomy-of-a-select-statement-part-2-the-hierarchical-query-clause\/"},"modified":"2021-07-14T13:07:24","modified_gmt":"2021-07-14T13:07:24","slug":"anatomy-of-a-select-statement-part-2-the-hierarchical-query-clause","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/oracle-databases\/anatomy-of-a-select-statement-part-2-the-hierarchical-query-clause\/","title":{"rendered":"Anatomy Of A SELECT Statement \u2013 Part 2: The Hierarchical Query Clause"},"content":{"rendered":"<p>My wife and I just welcomed our first child to the world. No, there\u2019s no need to congratulate me; as Chris Rock once said, it\u2019s no big deal, even cockroaches have babies. However, it does mean that I\u2019ve often been up at 3 a.m. rocking my son, mumbling nursery rhymes to him.\u00a0 Which, of course, always has me thinking of hierarchical queries. Of course.<\/p>\n<p>But first, a definition.\u00a0 A hierarchical query is a type of recursive query that returns a resultset that displays the natural relationship of data.\u00a0 Or, if you like pretty mental pictures, hierarchical queries return datasets in which each record is (potentially) holding hands with the record before it.<\/p>\n<p>Using a vanilla select query, you can find out from the EMP table all the staff for whom King is their manager. However, you will then need to run a second select statement to find out all the staff who report to <em>them.<\/em> Using a hierarchical query, we can find out, in one move, who reports to King, who reports to them and who reports to <em>them.<\/em> King is Jones\u2019s manager; Jones is Scott\u2019s manager; Scott is Adams\u2019 manager\u2026<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5599\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat1.png\" alt=\"Database record\" width=\"311\" height=\"306\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat1.png 311w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat1-300x295.png 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat1-60x60.png 60w\" sizes=\"auto, (max-width: 311px) 100vw, 311px\" \/><\/p>\n<p>Which brings us back to 3 a.m with me singing blearily to my baby: <em>the toe bone\u2019s connected to foot bone; the foot bone\u2019s connected to the ankle bone; the ankle bone\u2019s connected to the shin bone\u2026<\/em><\/p>\n<p>Hierarchical data.\u00a0 It\u2019s everywhere, even in nursery rhymes.<\/p>\n<h5>Syntax and Keywords<\/h5>\n<p>To query hierarchical data, you will need to refer to a family of keywords and build a hierarchical query clause. \u00a0\u00a0The hierarchical query clause comes, in a SELECT statement, right after the where clause.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5600\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat2.png\" alt=\"SELECT FROM\" width=\"454\" height=\"189\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat2.png 454w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat2-300x125.png 300w\" sizes=\"auto, (max-width: 454px) 100vw, 454px\" \/><\/p>\n<p>As I said, there are a few keywords we&#8217;ll need to get acquainted with in order to understand hierarchical querying. The best way to find out what they are is to zoom in on the hierarchical query clause and study its syntax.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-5601 size-full\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat3-e1434449690351.png\" alt=\"Hierarchical query\" width=\"600\" height=\"116\" \/><\/p>\n<p><strong>CONNECT BY<\/strong> tells Oracle what the relationship between the parent row and the child row should be. To do this we use a simple condition of the type which we might typically use in a WHERE clause; the only difference here is that we must also use the <strong>PRIOR<\/strong> keyword to indicate the parent.<\/p>\n<p>In our earlier example from the EMP table, because we wanted to show managers followed by their employees, the manager row would be the parent, with the employee being the child. This means that whatever was the employee id in the previous \u2013 <em>prior \u00ad- <\/em>\u00a0row would be the manager id in the next.<\/p>\n<pre>CONNECT BY PRIOR empno = mgr<\/pre>\n<p><strong>START WITH<\/strong> tells Oracle what is the <em>root<\/em> record of our hierarchy. It does this by also employing a condition.<\/p>\n<p>In our earlier example, we wanted to start off with the big kahuna, the man with no manager.<\/p>\n<pre>START WITH mgr IS NULL<\/pre>\n<p>So if we throw it all together, we end up with:<\/p>\n<pre>SELECT\u00a0 ename \"Employee\",\u00a0 empno \"Employee ID\",\u00a0 mgr \"Manager ID\"\r\nFROM emp\r\nCONNECT BY PRIOR empno = mgr\r\nSTART WITH mgr IS NULL;<\/pre>\n<p>We&#8217;ve asked our query to start with the big boss, and that&#8217;s quite clear. However, from the third record things become a little less clear, as it is not immediately obvious if Scott reports to Jones or directly to King. The <strong>LEVEL<\/strong> pseudocolumn returns a number indicating what level of the hierarchy the record is.<\/p>\n<p>Another way to show a node&#8217;s position in the hierarchy is to use the <strong>SYS_CONNECT_BY_PATH<\/strong> function. This function returns the full path from the root node to the current node, and has the following syntax:<\/p>\n<pre>SYS_CONNECT_BY_PATH (column , delimiter)<\/pre>\n<pre>SELECT\u00a0 ename \"Employee\", \u00a0LEVEL, SYS_CONNECT_BY_PATH (ename, '\/') \"Path\"\r\nFROM emp\r\nCONNECT BY PRIOR empno = mgr\r\nSTART WITH mgr IS NULL;<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5602\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat4.png\" alt=\"Employee Database\" width=\"328\" height=\"308\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat4.png 328w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2015\/06\/anat4-300x282.png 300w\" sizes=\"auto, (max-width: 328px) 100vw, 328px\" \/><\/p>\n<p>Blake&#8217;s a busy boy. He has five direct reports \u2013 Allen, Ward, Martin, Turner and James. If we wanted to sort that list alphabetically, we would not be able to use the normal ORDER BY clause, as that would override the hierarchical order created by the CONNECT BY and we&#8217;ll end up with Adams on top and King somewhere in the middle. (GROUP BY overrides the hierarchy too.) To sort within the bounds of our CONNECT BY we must use a different clause:<\/p>\n<pre>ORDER SIBLINGS BY<\/pre>\n<h5>NOCYCLE<\/h5>\n<p>So far we&#8217;ve been working with nice, tame data. Our lines are straight, and our hierarchical tree is uncomplicated. However, the real world can be messy like a plate of spaghetti. Imagine if King, instead of being the overall boss, had to report to a board headed by Jones. That would mean that while King is Jones&#8217; boss, Jones is also King&#8217;s boss. If we update the EMP table to reflect this, and rerun our query, we get the following error:<\/p>\n<pre>ORA-01436: CONNECT BY loop in user data<\/pre>\n<p>To tell Oracle to proceed in spite of loops in our data, we need to modify our CONNECT BY statement to CONNECT BY <em>NOCYCLE<\/em>.<\/p>\n<p>And, if we wish to identify records where any such loops have been resolved, we would need to include the <strong>CONNECT_BY_ISCYCLE<\/strong> pseudocolumn in our query.\u00a0 CONNECT_BY_ISCYCLE returns\u00a0 1 where it identifies a loop; otherwise it returns 0.<\/p>\n<pre>SELECT\u00a0 ename \"Employee\", empno, mgr,\u00a0 CONNECT_BY_ISCYCLE, SYS_CONNECT_BY_PATH (ename, '\/') \"Path\"\r\nFROM emp\r\nCONNECT BY NOCYCLE PRIOR empno = mgr\r\nSTART WITH ename = 'KING'\r\nORDER SIBLINGS BY ename;\r\n<\/pre>\n<h5>Conclusion<\/h5>\n<p>So that&#8217;s it.<\/p>\n<p>Except that it&#8217;s not.\u00a0 Since 11gR2 we have been able to query hierarchical data using recursive subquery factoring clauses or, in other words, the WITH clause.\u00a0 This brings the ANSI standard to Oracle.<\/p>\n<p>I&#8217;ll tell you how it all works in the next part of this article.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>My wife and I just welcomed our first child to the world. No, there\u2019s no need to congratulate me; as Chris Rock once said, it\u2019s no big deal, even cockroaches have babies. However, it does mean that I\u2019ve often been up at 3 a.m. rocking my son, mumbling nursery rhymes to him.\u00a0 Which, of course, always has me thinking of&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":[48416,48497,48520],"coauthors":[],"class_list":["post-73162","post","type-post","status-publish","format-standard","hentry","category-oracle-databases","tag-hierarchical-data","tag-select-statements","tag-syntax"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73162","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=73162"}],"version-history":[{"count":1,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73162\/revisions"}],"predecessor-version":[{"id":91655,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73162\/revisions\/91655"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=73162"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=73162"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=73162"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=73162"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}