<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Sql on Dat a Engineer</title><link>https://note.datengineer.dev/tags/sql/</link><description>Recent content in Sql on Dat a Engineer</description><image><title>Dat a Engineer</title><url>https://note.datengineer.dev/images/cover.png</url><link>https://note.datengineer.dev/images/cover.png</link></image><generator>Hugo -- 0.147.5</generator><language>en-us</language><lastBuildDate>Sun, 19 Jan 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://note.datengineer.dev/tags/sql/index.xml" rel="self" type="application/rss+xml"/><item><title>PIVOT and Dynamic PIVOT in SQL - Advanced SQL for analytics</title><link>https://note.datengineer.dev/posts/pivot-and-dynamic-pivot-in-sql-advanced-sql-for-analytics/</link><pubDate>Sun, 19 Jan 2025 00:00:00 +0000</pubDate><guid>https://note.datengineer.dev/posts/pivot-and-dynamic-pivot-in-sql-advanced-sql-for-analytics/</guid><description>Explore advanced SQL techniques static and dynamic PIVOT to transform and analyze data beyond the basic SELECT FROM WHERE queries. Learn how to apply them in real-world analytics.</description><content:encoded><![CDATA[<p>As a data engineer, a typical working day for me, apart from meetings, is full of <code>SELECT</code>, <code>FROM</code> and <code>WHERE</code>. But these basic statements are not enough, especially for the complex ad hoc analysis that is increasingly common nowadays.</p>
<p>SQL is a powerful language. It is a declarative language where we define what we want and the engine finds a way to achieve it. The language is evolving to adapt to the increasing variety of analysis needs. I wrote an article about an <a href="../recursive-ctes-and-connect-by-in-sql-to-query-hierarchical-data">advanced SQL feature to deal with hierarchical data</a>. And today, let&rsquo;s explore another beyond-the-basic feature: PIVOT.</p>
<h2 id="problem-statement">Problem Statement</h2>
<p>Imagine you are working as a data engineer for a retail company. The company wants to analyze product sales data to identify trends and opportunities for growth. The data is stored in a table called <code>Sales</code> with the following structure:</p>
<table>
  <thead>
      <tr>
          <th>ProductID</th>
          <th>Date</th>
          <th>Amount</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>101</td>
          <td>2024-01-10</td>
          <td>300</td>
      </tr>
      <tr>
          <td>101</td>
          <td>2024-12-15</td>
          <td>500</td>
      </tr>
      <tr>
          <td>101</td>
          <td>2025-01-15</td>
          <td>700</td>
      </tr>
      <tr>
          <td>101</td>
          <td>2025-02-01</td>
          <td>1100</td>
      </tr>
      <tr>
          <td>102</td>
          <td>2024-02-20</td>
          <td>800</td>
      </tr>
      <tr>
          <td>102</td>
          <td>2024-11-03</td>
          <td>400</td>
      </tr>
      <tr>
          <td>102</td>
          <td>2025-01-20</td>
          <td>900</td>
      </tr>
      <tr>
          <td>102</td>
          <td>2025-02-22</td>
          <td>650</td>
      </tr>
      <tr>
          <td>103</td>
          <td>2023-07-25</td>
          <td>1200</td>
      </tr>
      <tr>
          <td>103</td>
          <td>2024-08-15</td>
          <td>1500</td>
      </tr>
      <tr>
          <td>103</td>
          <td>2025-02-10</td>
          <td>1250</td>
      </tr>
      <tr>
          <td>104</td>
          <td>2023-12-05</td>
          <td>400</td>
      </tr>
      <tr>
          <td>104</td>
          <td>2024-06-30</td>
          <td>800</td>
      </tr>
      <tr>
          <td>104</td>
          <td>2025-01-30</td>
          <td>300</td>
      </tr>
      <tr>
          <td>104</td>
          <td>2025-02-25</td>
          <td>500</td>
      </tr>
  </tbody>
</table>
<p>This structure is not good for reports. The company wants this data served in a format where years are represented as columns for easier comparison across products.</p>
<h2 id="group-by---the-amateur-way">GROUP BY - The Amateur Way</h2>
<p>A very straightforward approach to this problem is to use the <code>GROUP BY</code> statement. We will group by <code>ProductID</code>, and we will get the sum column for each month. Below is a SQL Server example. Other SQL engines should have similar syntax.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">select</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">ProductID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">,</span><span class="k">sum</span><span class="p">(</span><span class="n">iif</span><span class="p">(</span><span class="k">year</span><span class="p">(</span><span class="nb">Date</span><span class="p">)</span><span class="o">=</span><span class="mi">2023</span><span class="p">,</span><span class="w"> </span><span class="n">Amount</span><span class="p">,</span><span class="w"> </span><span class="k">null</span><span class="p">))</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="p">[</span><span class="mi">2023</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">,</span><span class="k">sum</span><span class="p">(</span><span class="n">iif</span><span class="p">(</span><span class="k">year</span><span class="p">(</span><span class="nb">Date</span><span class="p">)</span><span class="o">=</span><span class="mi">2024</span><span class="p">,</span><span class="w"> </span><span class="n">Amount</span><span class="p">,</span><span class="w"> </span><span class="k">null</span><span class="p">))</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="p">[</span><span class="mi">2024</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">,</span><span class="k">sum</span><span class="p">(</span><span class="n">iif</span><span class="p">(</span><span class="k">year</span><span class="p">(</span><span class="nb">Date</span><span class="p">)</span><span class="o">=</span><span class="mi">2025</span><span class="p">,</span><span class="w"> </span><span class="n">Amount</span><span class="p">,</span><span class="w"> </span><span class="k">null</span><span class="p">))</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="p">[</span><span class="mi">2025</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">from</span><span class="w"> </span><span class="n">Sales</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">group</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">ProductID</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div>

<p><details >
  <summary markdown="span"><em>GROUP BY query result</em></summary>
  <table>
  <thead>
      <tr>
          <th style="text-align: right">ProductID</th>
          <th style="text-align: right">2023</th>
          <th style="text-align: right">2024</th>
          <th style="text-align: right">2025</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">101</td>
          <td style="text-align: right"><em>null</em></td>
          <td style="text-align: right">800</td>
          <td style="text-align: right">1800</td>
      </tr>
      <tr>
          <td style="text-align: right">102</td>
          <td style="text-align: right"><em>null</em></td>
          <td style="text-align: right">1200</td>
          <td style="text-align: right">1550</td>
      </tr>
      <tr>
          <td style="text-align: right">103</td>
          <td style="text-align: right">1200</td>
          <td style="text-align: right">1500</td>
          <td style="text-align: right">1250</td>
      </tr>
      <tr>
          <td style="text-align: right">104</td>
          <td style="text-align: right">400</td>
          <td style="text-align: right">800</td>
          <td style="text-align: right">800</td>
      </tr>
  </tbody>
</table>

</details></p>

<p>At first glance, it&rsquo;s simple, and it works. Sometimes just working is enough.</p>
<h2 id="sql-pivot---the-complex-way">SQL PIVOT - The Complex Way</h2>
<p><code>PIVOT</code> is a operator in SQL that allows you to transform rows into columns. This transformation is particularly useful when summarizing data and creating a more interpretable format for analysis. The below SQL Server query achieves similar results:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">select</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="o">*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">from</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">select</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">ProductID</span><span class="p">,</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">year</span><span class="p">(</span><span class="nb">Date</span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="k">Year</span><span class="p">,</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">Amount</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">from</span><span class="w"> </span><span class="n">Sales</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">ToPivotSales</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">sum</span><span class="p">(</span><span class="n">Amount</span><span class="p">)</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="k">Year</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="p">([</span><span class="mi">2023</span><span class="p">],</span><span class="w"> </span><span class="p">[</span><span class="mi">2024</span><span class="p">],</span><span class="w"> </span><span class="p">[</span><span class="mi">2025</span><span class="p">])</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">PivotedSales</span><span class="w">
</span></span></span></code></pre></div>

<p><details >
  <summary markdown="span"><em>PIVOT query result</em></summary>
  <table>
  <thead>
      <tr>
          <th style="text-align: right">ProductID</th>
          <th style="text-align: right">2023</th>
          <th style="text-align: right">2024</th>
          <th style="text-align: right">2025</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">101</td>
          <td style="text-align: right"><em>null</em></td>
          <td style="text-align: right">800</td>
          <td style="text-align: right">1800</td>
      </tr>
      <tr>
          <td style="text-align: right">102</td>
          <td style="text-align: right"><em>null</em></td>
          <td style="text-align: right">1200</td>
          <td style="text-align: right">1550</td>
      </tr>
      <tr>
          <td style="text-align: right">103</td>
          <td style="text-align: right">1200</td>
          <td style="text-align: right">1500</td>
          <td style="text-align: right">1250</td>
      </tr>
      <tr>
          <td style="text-align: right">104</td>
          <td style="text-align: right">400</td>
          <td style="text-align: right">800</td>
          <td style="text-align: right">800</td>
      </tr>
  </tbody>
</table>

</details></p>

<p>To do <code>PIVOT</code>, we first need a subquery to specify the columns we need. In this case they are <code>ProductID</code>, <code>Year</code> and <code>Amount</code>. If you don&rsquo;t like subqueries, CTE (Common Table Expression) works as well.</p>
<p>In the <code>PIVOT</code> decalaration:</p>
<ul>
<li><code>sum(Amount)</code>: specifies that the aggregation function to be applied is <code>sum</code>, which will sum the <code>Amount</code> values.</li>
<li><code>for Year in ([2023], [2024], [2025])</code>: defines how the pivoting will occur:
<ul>
<li><code>for Year</code>: indicates that the values in the <code>Year</code> column will be used to create new columns in the result set.</li>
<li><code>in ([2023], [2024], [2025])</code>: specifies the specific years that will become the new columns in the result. Each of these years will have a corresponding column that contains the summed Amount for that year.</li>
</ul>
</li>
</ul>
<p>To be honest, I don&rsquo;t like the syntax of <code>PIVOT</code>. It is terrible to me. It involves subqueries and CTEs, it uses more levels of indentation, and it&rsquo;s harder to scan through. And if we look at the execution plan, it is not really faster than <code>GROUP BY</code>.</p>
<p>With that being said, <code>PIVOT</code> still has advantages over <code>GROUP BY</code> that it requires less boilerplate code. In the examples above, to add a new year to the query with <code>GROUP BY</code>, you have to copy, paste, and edit in 2 places. With <code>PIVOT</code>, all you have to do is add a new value to the list. This makes <code>PIVOT</code> shine in situations where we have to deal with a long list of values.</p>
<h2 id="dynamic-pivot---the-hacker-way">Dynamic PIVOT - The Hacker Way</h2>
<p>While both GROUP BY and PIVOT are useful, they have the limitation that you must explicitly specify the list of values. When the data is small, this is fine. But it becomes a problem when dealing with evolving, large data where you do not know or do not want to manually list all possible values. Imagine you build a report of annual sales, you clearly don&rsquo;t want to update the query every year.</p>
<p>Dynamic PIVOT is a technique that allows us to pivot data without hard-coding the pivot column values. It is not a standard SQL operation. Therefore, the syntax may vary between different SQL engines. In Snowflake SQL, you can achieve dynamic pivoting by something as simple as this.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="p">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">pivot</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">sum</span><span class="p">(</span><span class="n">Amount</span><span class="p">)</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="k">Year</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="p">(</span><span class="k">any</span><span class="w"> </span><span class="k">order</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="k">Year</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>Most other SQL engines don&rsquo;t offer this level of simplicity. They require a bit of complexity. Below is a SQL Server query example.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">declare</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="o">@</span><span class="n">cols</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">nvarchar</span><span class="p">(</span><span class="k">max</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="o">@</span><span class="n">query</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">nvarchar</span><span class="p">(</span><span class="k">max</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">select</span><span class="w"> </span><span class="o">@</span><span class="n">cols</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">string_agg</span><span class="p">(</span><span class="n">quotename</span><span class="p">(</span><span class="k">Year</span><span class="p">),</span><span class="w"> </span><span class="s1">&#39;,&#39;</span><span class="p">)</span><span class="w"> </span><span class="n">within</span><span class="w"> </span><span class="k">group</span><span class="w"> </span><span class="p">(</span><span class="k">order</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="k">Year</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">from</span><span class="w"> </span><span class="p">(</span><span class="k">select</span><span class="w"> </span><span class="k">distinct</span><span class="w"> </span><span class="k">year</span><span class="p">(</span><span class="nb">Date</span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="k">Year</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">Sales</span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">YearList</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">set</span><span class="w"> </span><span class="o">@</span><span class="n">query</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="s1">&#39;select *
</span></span></span><span class="line"><span class="cl"><span class="s1">    from (
</span></span></span><span class="line"><span class="cl"><span class="s1">        select ProductID, year(Date) as Year, Amount
</span></span></span><span class="line"><span class="cl"><span class="s1">        from Sales
</span></span></span><span class="line"><span class="cl"><span class="s1">    ) as ToPivotSales pivot (
</span></span></span><span class="line"><span class="cl"><span class="s1">        sum(Amount) for Year in (&#39;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="o">@</span><span class="n">cols</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">&#39;)
</span></span></span><span class="line"><span class="cl"><span class="s1">    ) as PivotedSales;&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">exec</span><span class="w"> </span><span class="n">sp_executesql</span><span class="w"> </span><span class="o">@</span><span class="n">query</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div>

<p><details >
  <summary markdown="span"><em>Dynamic PIVOT query result</em></summary>
  <table>
  <thead>
      <tr>
          <th style="text-align: right">ProductID</th>
          <th style="text-align: right">2023</th>
          <th style="text-align: right">2024</th>
          <th style="text-align: right">2025</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">101</td>
          <td style="text-align: right"><em>null</em></td>
          <td style="text-align: right">800</td>
          <td style="text-align: right">1800</td>
      </tr>
      <tr>
          <td style="text-align: right">102</td>
          <td style="text-align: right"><em>null</em></td>
          <td style="text-align: right">1200</td>
          <td style="text-align: right">1550</td>
      </tr>
      <tr>
          <td style="text-align: right">103</td>
          <td style="text-align: right">1200</td>
          <td style="text-align: right">1500</td>
          <td style="text-align: right">1250</td>
      </tr>
      <tr>
          <td style="text-align: right">104</td>
          <td style="text-align: right">400</td>
          <td style="text-align: right">800</td>
          <td style="text-align: right">800</td>
      </tr>
  </tbody>
</table>

</details></p>

<p>Although the code is not pleasing to eyes, the concept is simple. We need an additional step to find all the unique values and store them in a variable. Then we construct the query with the above list of unique values. Execute it and we get the expected result.</p>
<h2 id="final-thought">Final Thought</h2>
<p>Mastering SQL is not easy. SQL is more than just a query language; it&rsquo;s a powerful tool that, when used effectively, can turn raw data into actionable intelligence. Advanced SQL techniques such as <code>PIVOT</code> are not very common in our day-to-day work. But we should know what we have in our toolbox. So that we can quickly select the right tool from the toolbox where the right job applies.</p>
<p><em>* You can find the execution of SQL query examples in this post at <a href="https://dbfiddle.uk/2jD1lHkL" rel="nofollow"> https://dbfiddle.uk/2jD1lHkL </a>
</em></p>
]]></content:encoded></item><item><title>Recursive CTEs and CONNECT BY in SQL to query Hierarchical data</title><link>https://note.datengineer.dev/posts/recursive-ctes-and-connect-by-in-sql-to-query-hierarchical-data/</link><pubDate>Tue, 20 Feb 2024 00:00:00 +0000</pubDate><guid>https://note.datengineer.dev/posts/recursive-ctes-and-connect-by-in-sql-to-query-hierarchical-data/</guid><description>Discover the concept of hierarchical data in SQL and see real-life examples. Learn how to query hierarchical data and extract insights with advanced SQL features: Recursive CTEs and CONNECT BY.</description><content:encoded><![CDATA[<p>In database design, the idea of hierarchical data represents relationships between entities as a tree-like structure. This type of data model is widely used in many domains, such as file systems, organizational structure, etc. When dealing with hierarchical data, it is crucial to efficiently query and extract information about the relationships between entities. In this post, we will explore two powerful SQL tools for querying hierarchical data: recursive Common Table Expressions (CTEs) and the CONNECT BY clause.</p>
<h2 id="hierarchical-data">Hierarchical Data</h2>
<p>Hierarchical data represents a natural parent-child relationship that is often visualized in the form of a tree structure. Imagine a family tree: grandparents on top, parents in the middle, and you and siblings at the bottom, all connected. That&rsquo;s hierarchical data! It organizes information in levels, making it easy to understand how things are related. The most popular real-life example of hierarchical data is employee-manager relationships. Every employee is managed by a manager. And that manager is also an employee and (again) is managed by another manager who is also an employee.</p>
<p><img alt="Hierarchical Data example Employee-Manager relationship" loading="lazy" src="/posts/recursive-ctes-and-connect-by-in-sql-to-query-hierarchical-data/images/hierarchical-data-exampl-employee-manager-sql.png"></p>
<h2 id="hierarchical-data-representation-in-sql">Hierarchical Data representation in SQL</h2>
<p>Relational models perform best with flat tables with rows and columns, not tree-like structures. However, people developed techniques to represent hierarchical data in SQL. The most common approach is referencing using foreign key. In the above example, we will add a column manager_id referring to the person who managed this employee to the employee table.</p>
<table>
  <thead>
      <tr>
          <th>EMPLOYEE_ID</th>
          <th>NAME</th>
          <th>SALARY</th>
          <th>MANAGER_ID</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td>Adam</td>
          <td>60000</td>
          <td>NULL</td>
      </tr>
      <tr>
          <td>2</td>
          <td>John</td>
          <td>30000</td>
          <td>1</td>
      </tr>
      <tr>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
          <td>&hellip;</td>
      </tr>
  </tbody>
</table>
<p><em>*Example SQL table representing hierarchical data structure</em></p>
<h2 id="querying-hierarchical-data">Querying Hierarchical Data</h2>
<p>When querying hierarchical data, we often want to understand the relationship in both directions: who manages whom and who is managed by whom. However, querying hierarchical data is tricky because we don&rsquo;t know the depth of the tree, i.e. how many levels of hierarchy there are. Before we look at how to do this in SQL, let&rsquo;s prepare some data to work with. Note that all SQL code in this post is Oracle, as it natively supports CONNECT BY. Other RDBMS SQL should be similar.</p>


<p><details >
  <summary markdown="span"><em>Example data</em></summary>
  <table>
  <thead>
      <tr>
          <th style="text-align: right">EMPLOYEE_ID</th>
          <th>NAME</th>
          <th style="text-align: right">SALARY</th>
          <th style="text-align: right">MANAGER_ID</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td>Adam</td>
          <td style="text-align: right">60000</td>
          <td style="text-align: right">null</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Sarah</td>
          <td style="text-align: right">70000</td>
          <td style="text-align: right">null</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td>David</td>
          <td style="text-align: right">50000</td>
          <td style="text-align: right">1</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td>Emily</td>
          <td style="text-align: right">55000</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Michael</td>
          <td style="text-align: right">45000</td>
          <td style="text-align: right">1</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td>Jessica</td>
          <td style="text-align: right">50000</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td>Ben</td>
          <td style="text-align: right">35000</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td>Olivia</td>
          <td style="text-align: right">37000</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>Charles</td>
          <td style="text-align: right">32000</td>
          <td style="text-align: right">5</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td>Sophia</td>
          <td style="text-align: right">33000</td>
          <td style="text-align: right">6</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td>Alex</td>
          <td style="text-align: right">37000</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">12</td>
          <td>Maya</td>
          <td style="text-align: right">38000</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">13</td>
          <td>Daniel</td>
          <td style="text-align: right">35000</td>
          <td style="text-align: right">5</td>
      </tr>
      <tr>
          <td style="text-align: right">14</td>
          <td>Isabella</td>
          <td style="text-align: right">36000</td>
          <td style="text-align: right">6</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>Ryan</td>
          <td style="text-align: right">25000</td>
          <td style="text-align: right">7</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td>Chloe</td>
          <td style="text-align: right">26000</td>
          <td style="text-align: right">8</td>
      </tr>
      <tr>
          <td style="text-align: right">17</td>
          <td>Noah</td>
          <td style="text-align: right">24000</td>
          <td style="text-align: right">9</td>
      </tr>
      <tr>
          <td style="text-align: right">18</td>
          <td>Mia</td>
          <td style="text-align: right">25000</td>
          <td style="text-align: right">10</td>
      </tr>
      <tr>
          <td style="text-align: right">19</td>
          <td>Liam</td>
          <td style="text-align: right">26000</td>
          <td style="text-align: right">11</td>
      </tr>
      <tr>
          <td style="text-align: right">20</td>
          <td>Evelyn</td>
          <td style="text-align: right">27000</td>
          <td style="text-align: right">12</td>
      </tr>
      <tr>
          <td style="text-align: right">21</td>
          <td>William</td>
          <td style="text-align: right">25000</td>
          <td style="text-align: right">13</td>
      </tr>
      <tr>
          <td style="text-align: right">22</td>
          <td>Charlotte</td>
          <td style="text-align: right">26000</td>
          <td style="text-align: right">14</td>
      </tr>
      <tr>
          <td style="text-align: right">23</td>
          <td>Ethan</td>
          <td style="text-align: right">27000</td>
          <td style="text-align: right">7</td>
      </tr>
      <tr>
          <td style="text-align: right">24</td>
          <td>Ava</td>
          <td style="text-align: right">28000</td>
          <td style="text-align: right">8</td>
      </tr>
      <tr>
          <td style="text-align: right">25</td>
          <td>Lucas</td>
          <td style="text-align: right">26000</td>
          <td style="text-align: right">9</td>
      </tr>
      <tr>
          <td style="text-align: right">26</td>
          <td>Amelia</td>
          <td style="text-align: right">27000</td>
          <td style="text-align: right">10</td>
      </tr>
      <tr>
          <td style="text-align: right">27</td>
          <td>Mason</td>
          <td style="text-align: right">28000</td>
          <td style="text-align: right">11</td>
      </tr>
      <tr>
          <td style="text-align: right">28</td>
          <td>Harper</td>
          <td style="text-align: right">29000</td>
          <td style="text-align: right">12</td>
      </tr>
      <tr>
          <td style="text-align: right">29</td>
          <td>Logan</td>
          <td style="text-align: right">27000</td>
          <td style="text-align: right">13</td>
      </tr>
      <tr>
          <td style="text-align: right">30</td>
          <td>Sofia</td>
          <td style="text-align: right">28000</td>
          <td style="text-align: right">14</td>
      </tr>
  </tbody>
</table>

</details></p>

<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">EMPLOYEES</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="n">EMPLOYEE_ID</span><span class="w"> </span><span class="nb">NUMBER</span><span class="w"> </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="n">NAME</span><span class="w"> </span><span class="n">VARCHAR2</span><span class="p">(</span><span class="mi">50</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="n">SALARY</span><span class="w"> </span><span class="nb">NUMBER</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="n">MANAGER_ID</span><span class="w"> </span><span class="nb">NUMBER</span><span class="w"> </span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">EMPLOYEES</span><span class="p">(</span><span class="n">EMPLOYEE_ID</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">INSERT</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="n">EMPLOYEES</span><span class="w"> </span><span class="k">VALUES</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Adam&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">60000</span><span class="p">,</span><span class="w"> </span><span class="k">NULL</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Sarah&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">70000</span><span class="p">,</span><span class="w"> </span><span class="k">NULL</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;David&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">50000</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Emily&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">55000</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">5</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Michael&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">45000</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">6</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Jessica&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">50000</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">7</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Ben&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">35000</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">8</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Olivia&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">37000</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">9</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Charles&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">32000</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Sophia&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">33000</span><span class="p">,</span><span class="w"> </span><span class="mi">6</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">11</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Alex&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">37000</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Maya&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">38000</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">13</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Daniel&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">35000</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">14</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Isabella&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">36000</span><span class="p">,</span><span class="w"> </span><span class="mi">6</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">15</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Ryan&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">25000</span><span class="p">,</span><span class="w"> </span><span class="mi">7</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">16</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Chloe&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">26000</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">17</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Noah&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">24000</span><span class="p">,</span><span class="w"> </span><span class="mi">9</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">18</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Mia&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">25000</span><span class="p">,</span><span class="w"> </span><span class="mi">10</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">19</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Liam&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">26000</span><span class="p">,</span><span class="w"> </span><span class="mi">11</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">20</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Evelyn&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">27000</span><span class="p">,</span><span class="w"> </span><span class="mi">12</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">21</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;William&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">25000</span><span class="p">,</span><span class="w"> </span><span class="mi">13</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">22</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Charlotte&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">26000</span><span class="p">,</span><span class="w"> </span><span class="mi">14</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">23</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Ethan&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">27000</span><span class="p">,</span><span class="w"> </span><span class="mi">7</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">24</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Ava&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">28000</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">25</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Lucas&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">26000</span><span class="p">,</span><span class="w"> </span><span class="mi">9</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">26</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Amelia&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">27000</span><span class="p">,</span><span class="w"> </span><span class="mi">10</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">27</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Mason&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">28000</span><span class="p">,</span><span class="w"> </span><span class="mi">11</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">28</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Harper&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">29000</span><span class="p">,</span><span class="w"> </span><span class="mi">12</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">29</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Logan&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">27000</span><span class="p">,</span><span class="w"> </span><span class="mi">13</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="mi">30</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Sofia&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">28000</span><span class="p">,</span><span class="w"> </span><span class="mi">14</span><span class="p">);</span><span class="w">
</span></span></span></code></pre></div><p><img alt="Hierarchical Data example in SQL query" loading="lazy" src="/posts/recursive-ctes-and-connect-by-in-sql-to-query-hierarchical-data/images/hierarchical-data-examples-in-sql-query.jpg"></p>
<h3 id="problem-statement">Problem statement</h3>
<p>We want to look at it from two directions:</p>
<ul>
<li><strong>Problem 1</strong>: Start with individual employees and follow the ladder, revealing who manages them, their manager&rsquo;s manager, and so on, all the way to the top.</li>
<li><strong>Problem 2</strong>: Stand at the highest level and look down the hierarchy. For each employee, calculate the total salary of everyone under their direct or indirect management, like a salary pyramid.</li>
</ul>
<p>When looking at direct relationships (who manages who), a simple join clause will work. But things get tricky when we include multiple levels in the hierarchy.</p>
<h3 id="recursive-cte">Recursive CTE</h3>
<p>A recursive CTE (Common Table Expression) is a valuable feature in SQL. By referencing itself within the CTE, it allows you to query hierarchical data by repeating a process until it reaches every corner, making it an effective tool for querying and analyzing hierarchical data.</p>
<p>The recursive CTE syntax is not too different from non-recursive one.</p>
<p>Non-recursive CTE:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">WITH</span><span class="w"> </span><span class="n">CTE_NAME</span><span class="w"> </span><span class="p">(</span><span class="n">column_1</span><span class="p">,</span><span class="w"> </span><span class="n">column2</span><span class="p">,</span><span class="w"> </span><span class="p">...)</span><span class="w"> </span><span class="k">AS</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">-- CTE_QUERY_DEFINITION (SELECT ... FROM ... WHERE)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>Recursive CTE:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">WITH</span><span class="w"> </span><span class="n">CTE_NAME</span><span class="w"> </span><span class="p">(</span><span class="n">column_1</span><span class="p">,</span><span class="w"> </span><span class="n">column2</span><span class="p">,</span><span class="w"> </span><span class="p">...)</span><span class="w"> </span><span class="k">AS</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">-- ANCHOR_MEMBER (SELECT ... FROM ... WHERE BASE_LEVEL)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">UNION</span><span class="w"> </span><span class="p">(</span><span class="k">ALL</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">-- RECURSIVE_MEMBER (SELECT ... FROM (referrence to CTE_NAME) WHERE ...)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>The definition of a recursive CTE consists of two parts. The anchor member or the initial query, which is executed once. This defines the starting point of the execution. The recursive query has the reference to the CTE itself and is executed recursively until it returns no result. And we need UNION or UNION ALL to combine the results. You will see how it work when use it to solve real problems.</p>
<h4 id="problem-1">Problem 1</h4>
<p>For each employee, we get the direct manager, the path from the highest-level manager, and the employee&rsquo;s current level.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">WITH</span><span class="w"> </span><span class="n">company_hierarchy</span><span class="w"> </span><span class="p">(</span><span class="n">EMPLOYEE_ID</span><span class="p">,</span><span class="w"> </span><span class="n">NAME</span><span class="p">,</span><span class="w"> </span><span class="n">MANAGER</span><span class="p">,</span><span class="w"> </span><span class="n">MANAGER_PATH</span><span class="p">,</span><span class="w"> </span><span class="n">EMPLOYEE_LEVEL</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">-- Base query. Select ALL employees with no manager
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">emp</span><span class="p">.</span><span class="n">EMPLOYEE_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="n">emp</span><span class="p">.</span><span class="n">NAME</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="k">NULL</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">MANAGER</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="s1">&#39;&#39;</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">MANAGER_PATH</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="mi">1</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">EMPLOYEE_LEVEL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">FROM</span><span class="w"> </span><span class="n">EMPLOYEES</span><span class="w"> </span><span class="n">emp</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">WHERE</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="w"> </span><span class="k">IS</span><span class="w"> </span><span class="k">NULL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">UNION</span><span class="w"> </span><span class="k">ALL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">-- Recursive query which refer to the CTE itself.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="c1">-- Query all employee who is managed directly by previous level in company_hierarchy
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">emp</span><span class="p">.</span><span class="n">EMPLOYEE_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="n">emp</span><span class="p">.</span><span class="n">NAME</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="n">com</span><span class="p">.</span><span class="n">NAME</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">MANAGER</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="n">com</span><span class="p">.</span><span class="n">MANAGER_PATH</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">com</span><span class="p">.</span><span class="n">NAME</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="s1">&#39;/&#39;</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">MANAGER_PATH</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="n">com</span><span class="p">.</span><span class="n">EMPLOYEE_LEVEL</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">EMPLOYEE_LEVEL</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">FROM</span><span class="w"> </span><span class="n">EMPLOYEES</span><span class="w"> </span><span class="n">emp</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">INNER</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">company_hierarchy</span><span class="w"> </span><span class="n">com</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">ON</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">com</span><span class="p">.</span><span class="n">EMPLOYEE_ID</span><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">company_hierarchy</span><span class="w">
</span></span></span></code></pre></div>

<p><details >
  <summary markdown="span"><em>Recursive CTE query result</em></summary>
  <table>
  <thead>
      <tr>
          <th style="text-align: right">EMPLOYEE_ID</th>
          <th>NAME</th>
          <th>MANAGER</th>
          <th>MANAGER_PATH</th>
          <th style="text-align: right">EMPLOYEE_LEVEL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td>Adam</td>
          <td>null</td>
          <td>null</td>
          <td style="text-align: right">1</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Sarah</td>
          <td>null</td>
          <td>null</td>
          <td style="text-align: right">1</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td>David</td>
          <td>Adam</td>
          <td>Adam/</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Michael</td>
          <td>Adam</td>
          <td>Adam/</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td>Emily</td>
          <td>Sarah</td>
          <td>Sarah/</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td>Jessica</td>
          <td>Sarah</td>
          <td>Sarah/</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td>Ben</td>
          <td>David</td>
          <td>Adam/David/</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td>Alex</td>
          <td>David</td>
          <td>Adam/David/</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>Charles</td>
          <td>Michael</td>
          <td>Adam/Michael/</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">13</td>
          <td>Daniel</td>
          <td>Michael</td>
          <td>Adam/Michael/</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td>Olivia</td>
          <td>Emily</td>
          <td>Sarah/Emily/</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">12</td>
          <td>Maya</td>
          <td>Emily</td>
          <td>Sarah/Emily/</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td>Sophia</td>
          <td>Jessica</td>
          <td>Sarah/Jessica/</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">14</td>
          <td>Isabella</td>
          <td>Jessica</td>
          <td>Sarah/Jessica/</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>Ryan</td>
          <td>Ben</td>
          <td>Adam/David/Ben/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">23</td>
          <td>Ethan</td>
          <td>Ben</td>
          <td>Adam/David/Ben/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">19</td>
          <td>Liam</td>
          <td>Alex</td>
          <td>Adam/David/Alex/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">27</td>
          <td>Mason</td>
          <td>Alex</td>
          <td>Adam/David/Alex/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">17</td>
          <td>Noah</td>
          <td>Charles</td>
          <td>Adam/Michael/Charles/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">25</td>
          <td>Lucas</td>
          <td>Charles</td>
          <td>Adam/Michael/Charles/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">21</td>
          <td>William</td>
          <td>Daniel</td>
          <td>Adam/Michael/Daniel/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">29</td>
          <td>Logan</td>
          <td>Daniel</td>
          <td>Adam/Michael/Daniel/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td>Chloe</td>
          <td>Olivia</td>
          <td>Sarah/Emily/Olivia/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">24</td>
          <td>Ava</td>
          <td>Olivia</td>
          <td>Sarah/Emily/Olivia/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">20</td>
          <td>Evelyn</td>
          <td>Maya</td>
          <td>Sarah/Emily/Maya/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">28</td>
          <td>Harper</td>
          <td>Maya</td>
          <td>Sarah/Emily/Maya/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">18</td>
          <td>Mia</td>
          <td>Sophia</td>
          <td>Sarah/Jessica/Sophia/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">26</td>
          <td>Amelia</td>
          <td>Sophia</td>
          <td>Sarah/Jessica/Sophia/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">22</td>
          <td>Charlotte</td>
          <td>Isabella</td>
          <td>Sarah/Jessica/Isabella/</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">30</td>
          <td>Sofia</td>
          <td>Isabella</td>
          <td>Sarah/Jessica/Isabella/</td>
          <td style="text-align: right">4</td>
      </tr>
  </tbody>
</table>

</details></p>

<p>The below picture illustrates how the recursive CTE works:</p>
<p><img alt="Recursive CTE in SQL Flowchart" loading="lazy" src="/posts/recursive-ctes-and-connect-by-in-sql-to-query-hierarchical-data/images/recursive-cte-in-sql-how-it-work-flowchart.png"></p>
<p>First, the anchor member or initial query was executed. <code>company_hierarchy</code> CTE contained 2 members with <code>MANAGER_ID IS NULL</code> and <code>EMPLOYEE_LEVEL=1</code>.</p>
<p>Then the recursive query was executed, joining the <code>EMPLOYEES</code> table with <code>company_hierarchy</code> to get all members managed by 2 employees currently in <code>company_hierarchy</code>. <code>company_hierarchy</code> was then set to all returned employees (EMPLOYEE_LEVEL=2).</p>
<p>We kept doing so until the recursive query returned nothing.</p>
<p>At the end, we <code>UNION ALL</code> all the results.</p>
<h4 id="problem-2">Problem 2</h4>
<p>This is a bit more difficult. Let&rsquo;s reread the <a href="#problem-statement">problem statement</a> and try yourself before reading my answer.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">WITH</span><span class="w"> </span><span class="n">company_explode</span><span class="w"> </span><span class="p">(</span><span class="n">MANAGER_ID</span><span class="p">,</span><span class="w"> </span><span class="n">EMPLOYEE_ID</span><span class="p">,</span><span class="w"> </span><span class="n">SALARY</span><span class="p">,</span><span class="w"> </span><span class="n">MANAGEMENT_DISTANCE</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">-- Base query. Select ALL employees
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">SELECT</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">emp</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="n">emp</span><span class="p">.</span><span class="n">EMPLOYEE_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="n">emp</span><span class="p">.</span><span class="n">SALARY</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="mi">1</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">MANAGEMENT_DISTANCE</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">FROM</span><span class="w"> </span><span class="n">EMPLOYEES</span><span class="w"> </span><span class="n">emp</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">UNION</span><span class="w"> </span><span class="k">ALL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">-- Recursive query. Select ALL managers manages the employees
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w">    </span><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">mgr</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="n">com</span><span class="p">.</span><span class="n">EMPLOYEE_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="n">com</span><span class="p">.</span><span class="n">SALARY</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">,</span><span class="n">com</span><span class="p">.</span><span class="n">MANAGEMENT_DISTANCE</span><span class="o">+</span><span class="mi">1</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">MANAGEMENT_DISTANCE</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">FROM</span><span class="w"> </span><span class="n">EMPLOYEES</span><span class="w"> </span><span class="n">mgr</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">INNER</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">company_explode</span><span class="w"> </span><span class="n">com</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">ON</span><span class="w"> </span><span class="n">mgr</span><span class="p">.</span><span class="n">EMPLOYEE_ID</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">com</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">MANAGER_ID</span><span class="p">,</span><span class="w"> </span><span class="k">SUM</span><span class="p">(</span><span class="n">SALARY</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">TOTAL_SALARY_MANAGED</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">company_explode</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">MANAGER_ID</span><span class="w">
</span></span></span></code></pre></div>

<p><details >
  <summary markdown="span"><em>Recursive CTE result</em></summary>
  <table>
  <thead>
      <tr>
          <th style="text-align: right">MANAGER_ID</th>
          <th style="text-align: right">TOTAL_SALARY_MANAGED</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">null</td>
          <td style="text-align: right">1037000</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td style="text-align: right">442000</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">465000</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td style="text-align: right">178000</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">185000</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">169000</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td style="text-align: right">175000</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td style="text-align: right">52000</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">54000</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td style="text-align: right">50000</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td style="text-align: right">52000</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td style="text-align: right">54000</td>
      </tr>
      <tr>
          <td style="text-align: right">12</td>
          <td style="text-align: right">56000</td>
      </tr>
      <tr>
          <td style="text-align: right">13</td>
          <td style="text-align: right">52000</td>
      </tr>
      <tr>
          <td style="text-align: right">14</td>
          <td style="text-align: right">54000</td>
      </tr>
  </tbody>
</table>

</details></p>

<p>The idea behind this solution is simple. First, explode the hierarchical structure of the data into a flattened table of all manager-employee pairs. Then calculate the sum with a simple <code>GROUP BY</code> clause.</p>
<h3 id="start-with--connect-by-">START WITH &hellip; CONNECT BY &hellip;</h3>
<p>CONNECT BY clause achieves similar functionality as a recursive Common Table Expression (CTE), but with a much shorter syntax. Let&rsquo;s take a look at it in action.</p>
<h4 id="problem-1-1">Problem 1</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">emp</span><span class="p">.</span><span class="n">EMPLOYEE_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">,</span><span class="n">emp</span><span class="p">.</span><span class="n">NAME</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">,</span><span class="n">mgr</span><span class="p">.</span><span class="n">NAME</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">MANAGER</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">,</span><span class="k">TRIM</span><span class="p">(</span><span class="k">LEADING</span><span class="w"> </span><span class="s1">&#39;/&#39;</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">SYS_CONNECT_BY_PATH</span><span class="p">(</span><span class="n">mgr</span><span class="p">.</span><span class="n">NAME</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;/&#39;</span><span class="p">))</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">MANAGER_PATH</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">,</span><span class="k">LEVEL</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">EMPLOYEE_LEVEL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">EMPLOYEES</span><span class="w"> </span><span class="n">emp</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">LEFT</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">EMPLOYEES</span><span class="w"> </span><span class="n">mgr</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">ON</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mgr</span><span class="p">.</span><span class="n">EMPLOYEE_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">START</span><span class="w"> </span><span class="k">WITH</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="w"> </span><span class="k">IS</span><span class="w"> </span><span class="k">NULL</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CONNECT</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="k">PRIOR</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">EMPLOYEE_ID</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="p">;</span><span class="w">
</span></span></span></code></pre></div>

<p><details >
  <summary markdown="span"><em>CONNECT BY query result</em></summary>
  <table>
  <thead>
      <tr>
          <th style="text-align: right">EMPLOYEE_ID</th>
          <th>NAME</th>
          <th>MANAGER</th>
          <th>MANAGER_PATH</th>
          <th style="text-align: right">EMPLOYEE_LEVEL</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td>Adam</td>
          <td>null</td>
          <td>null</td>
          <td style="text-align: right">1</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td>David</td>
          <td>Adam</td>
          <td>Adam</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td>Ben</td>
          <td>David</td>
          <td>Adam/David</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>Ryan</td>
          <td>Ben</td>
          <td>Adam/David/Ben</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">23</td>
          <td>Ethan</td>
          <td>Ben</td>
          <td>Adam/David/Ben</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td>Alex</td>
          <td>David</td>
          <td>Adam/David</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">19</td>
          <td>Liam</td>
          <td>Alex</td>
          <td>Adam/David/Alex</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">27</td>
          <td>Mason</td>
          <td>Alex</td>
          <td>Adam/David/Alex</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Michael</td>
          <td>Adam</td>
          <td>Adam</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>Charles</td>
          <td>Michael</td>
          <td>Adam/Michael</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">17</td>
          <td>Noah</td>
          <td>Charles</td>
          <td>Adam/Michael/Charles</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">25</td>
          <td>Lucas</td>
          <td>Charles</td>
          <td>Adam/Michael/Charles</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">13</td>
          <td>Daniel</td>
          <td>Michael</td>
          <td>Adam/Michael</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">21</td>
          <td>William</td>
          <td>Daniel</td>
          <td>Adam/Michael/Daniel</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">29</td>
          <td>Logan</td>
          <td>Daniel</td>
          <td>Adam/Michael/Daniel</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Sarah</td>
          <td>null</td>
          <td>null</td>
          <td style="text-align: right">1</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td>Emily</td>
          <td>Sarah</td>
          <td>Sarah</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td>Olivia</td>
          <td>Emily</td>
          <td>Sarah/Emily</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">16</td>
          <td>Chloe</td>
          <td>Olivia</td>
          <td>Sarah/Emily/Olivia</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">24</td>
          <td>Ava</td>
          <td>Olivia</td>
          <td>Sarah/Emily/Olivia</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">12</td>
          <td>Maya</td>
          <td>Emily</td>
          <td>Sarah/Emily</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">20</td>
          <td>Evelyn</td>
          <td>Maya</td>
          <td>Sarah/Emily/Maya</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">28</td>
          <td>Harper</td>
          <td>Maya</td>
          <td>Sarah/Emily/Maya</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td>Jessica</td>
          <td>Sarah</td>
          <td>Sarah</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td>Sophia</td>
          <td>Jessica</td>
          <td>Sarah/Jessica</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">18</td>
          <td>Mia</td>
          <td>Sophia</td>
          <td>Sarah/Jessica/Sophia</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">26</td>
          <td>Amelia</td>
          <td>Sophia</td>
          <td>Sarah/Jessica/Sophia</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">14</td>
          <td>Isabella</td>
          <td>Jessica</td>
          <td>Sarah/Jessica</td>
          <td style="text-align: right">3</td>
      </tr>
      <tr>
          <td style="text-align: right">22</td>
          <td>Charlotte</td>
          <td>Isabella</td>
          <td>Sarah/Jessica/Isabella</td>
          <td style="text-align: right">4</td>
      </tr>
      <tr>
          <td style="text-align: right">30</td>
          <td>Sofia</td>
          <td>Isabella</td>
          <td>Sarah/Jessica/Isabella</td>
          <td style="text-align: right">4</td>
      </tr>
  </tbody>
</table>

</details></p>

<h4 id="problem-2-1">Problem 2</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">emp</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">,</span><span class="k">SUM</span><span class="p">(</span><span class="n">CONNECT_BY_ROOT</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">SALARY</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">TOTAL_SALARY_MANAGED</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">EMPLOYEES</span><span class="w"> </span><span class="n">emp</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">CONNECT</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="k">PRIOR</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">EMPLOYEE_ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">emp</span><span class="p">.</span><span class="n">MANAGER_ID</span><span class="w">
</span></span></span></code></pre></div>

<p><details >
  <summary markdown="span"><em>CONNECT BY query result</em></summary>
  <table>
  <thead>
      <tr>
          <th style="text-align: right">MANAGER_ID</th>
          <th style="text-align: right">TOTAL_SALARY_MANAGED</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">null</td>
          <td style="text-align: right">1037000</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td style="text-align: right">442000</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td style="text-align: right">465000</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td style="text-align: right">178000</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td style="text-align: right">185000</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td style="text-align: right">169000</td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td style="text-align: right">175000</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td style="text-align: right">52000</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td style="text-align: right">54000</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td style="text-align: right">50000</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td style="text-align: right">52000</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td style="text-align: right">54000</td>
      </tr>
      <tr>
          <td style="text-align: right">12</td>
          <td style="text-align: right">56000</td>
      </tr>
      <tr>
          <td style="text-align: right">13</td>
          <td style="text-align: right">52000</td>
      </tr>
      <tr>
          <td style="text-align: right">14</td>
          <td style="text-align: right">54000</td>
      </tr>
  </tbody>
</table>

</details></p>

<p>Like magic, isn&rsquo;t it! The implementation details (what goes on behind the scenes) may be a bit different. But the way we reason about the query is the same as it is with Recursive CTEs. The <code>START WITH</code> clause provides the initial filter. The query is first executed with this filter, just like the anchor member in recursive CTEs. No <code>START WITH</code> clause means no filter is needed and the entire query is included in the first step. Then the <code>CONNECT BY</code> clauses specify how to connect between steps/levels in the hierarchical structure, just like recursive CTEs refer to themselves. Note that the <code>PRIOR</code> keyword implies that the following value is from the previous recursive step.</p>
<p>One of the main differences between the two approaches is how we select data. With <code>CONNECT BY</code>, we have to rely on built-in functions and operators to select the data we want. In the examples, we use the <code>SYS_CONNECT_BY_PATH</code> function to construct the path and the <code>CONNECT_BY_ROOT</code> operator to access the data in the first step.</p>
<h2 id="my-final-thoughts">My final thoughts</h2>
<p>Querying hierarchical data presents unique challenges that require specialized techniques to extract meaningful information. Recursive CTEs and the CONNECT BY clause offer powerful solutions for navigating and analyzing hierarchical data in SQL. One interesting fact is that CONNECT BY was actually around before Recursive CTEs.</p>
<p>While both techniques solve the same problem, we can only use one. Which one should you use? Well, it depends on you. If you hate subqueries and CTEs, and you like cool short magic queries, use CONNECT BY. However, being less verbose makes CONNECT BY harder to reason about. It&rsquo;s harder to write out that magic stuff, and harder to know why it doesn&rsquo;t work. Also, by writing the recursion yourself, recursive CTEs give you more control and flexibility. And note that not all RDBMS (SQL Server for example) support the CONNECT BY clause, even though it has been around for a long time.</p>
<p><em>* You can find the execution of SQL in this post at <a href="https://dbfiddle.uk/hXEzBJkX" rel="nofollow"> https://dbfiddle.uk/hXEzBJkX </a>
</em></p>
]]></content:encoded></item></channel></rss>