Hierarchical and recursive queries in SQL
A hierarchical query is a type of SQL query that handles hierarchical model data. They are special case of more general recursive fixpoint queries, which compute transitive closures.
In standard SQL:1999 hierarchical queries are implemented by way of recursive common table expressions (CTEs). Unlike the Oracle extension described below, the recursive CTEs were designed with fixpoint semantics from the beginning.[1] The recursive CTEs from the standard were relatively close to the existing implementation in IBM DB2 version 2.[1] Recursive CTEs are also supported by Microsoft SQL Server,[2] Firebird 2.1,[3] PostgreSQL 8.4+,[4] Oracle 11g Release 2, IBM Informix version 11.50+ and CUBRID.
An alternative syntax is the non-standard CONNECT BY
construct; it was introduced by Oracle in the 1980s.[5] Prior to Oracle 10g, the construct was only useful for traversing acyclic graphs because it returned an error on detecting any cycles; in version 10g Oracle introduced the NOCYCLE feature (and keyword), making the traversal work in the presence of cycles as well.[6]
Without Common-table-expressions or a connected-by clause it is possible to achieve hierarchical queries with user-defined recursive functions.[7]
Contents
CONNECT BY
CONNECT BY
is supported by EnterpriseDB,[8] Oracle database,[9] CUBRID,[10] IBM Informix[11] and DB2 although only if it is enabled as a compatibility mode.[12] The syntax is as follows:
SELECT select_list
FROM table_expression
[ WHERE ... ]
[ START WITH start_expression ]
CONNECT BY [NOCYCLE] { PRIOR child_expr = parent_expr | parent_expr = PRIOR child_expr }
[ ORDER SIBLINGS BY column1 [ ASC | DESC ] [, column2 [ ASC | DESC ] ] ...
[ GROUP BY ... ]
[ HAVING ... ]
...
- For example
SELECT LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || ename "employee", empno, mgr "manager"
FROM emp START WITH mgr IS NULL
CONNECT BY PRIOR empno = mgr;
The output from the above query would look like:
level | employee | empno | manager -------+-------------+-------+--------- 1 | KING | 7839 | 2 | JONES | 7566 | 7839 3 | SCOTT | 7788 | 7566 4 | ADAMS | 7876 | 7788 3 | FORD | 7902 | 7566 4 | SMITH | 7369 | 7902 2 | BLAKE | 7698 | 7839 3 | ALLEN | 7499 | 7698 3 | WARD | 7521 | 7698 3 | MARTIN | 7654 | 7698 3 | TURNER | 7844 | 7698 3 | JAMES | 7900 | 7698 2 | CLARK | 7782 | 7839 3 | MILLER | 7934 | 7782 (14 rows)
Pseudo-columns
- LEVEL
- CONNECT_BY_ISLEAF
- CONNECT_BY_ISCYCLE
- CONNECT_BY_ROOT
Unary operators
The following example returns the last name of each employee in department 10, each manager above that employee in the hierarchy, the number of levels between manager and employee, and the path between the two:
SELECT ename "Employee", CONNECT_BY_ROOT ename "Manager",
LEVEL-1 "Pathlen", SYS_CONNECT_BY_PATH(ename, '/') "Path"
FROM emp
WHERE LEVEL > 1 and deptno = 10
CONNECT BY PRIOR empno = mgr
ORDER BY "Employee", "Manager", "Pathlen", "Path";
Functions
SYS_CONNECT_BY_PATH
Common table expression
Lua error in package.lua at line 80: module 'strict' not found. A Common Table Expression, or CTE, (in SQL) is a temporary named result set, derived from a simple query and defined within the execution scope of a SELECT
, INSERT
, UPDATE
, or DELETE
statement.
CTEs can be thought of as alternatives to derived tables (subquery), views, and inline user-defined functions.
Common table expressions are supported by Teradata, DB2, Firebird,[13] Microsoft SQL Server, Oracle (with recursion since 11g release 2), PostgreSQL (since 8.4), SQLite (since 3.8.3), HyperSQL and H2 (experimental).[14] Oracle calls CTEs "subquery factoring".[15]
The syntax for a Recursive CTE is as follows:
WITH [RECURSIVE] with_query [, ...]
SELECT...
where with_query
‘s syntax is:
query_name [ (column_name [,...]) ] AS (SELECT ...)
Recursive CTEs (or "recursive subquery factoring"[16] in Oracle jargon) can be used to traverse relations (as graphs or trees) although the syntax is much more involved because there are no automatic pseudo-columns created (like LEVEL
above); if these are desired, they have to be created in the code. See MSDN documentation[2] or IBM documentation[17][18] for tutorial examples.
The RECURSIVE
keyword is not usually needed after WITH in systems other than PostgreSQL.[19]
In SQL:1999 a recursive (CTE) query may appear anywhere a query is allowed. It's possible, for example, to name the result using CREATE
[RECURSIVE
] VIEW
.[20] Using a CTE inside an INSERT INTO
, one can populate a table with data generated from a recursive query; random data generation is possible using this technique without using any procedural statements.[21]
An example of a recursive query computing the factorial of numbers from 0 to 9 is the following:
WITH temp (n, fact) AS
(SELECT 0, 1 -- Initial Subquery
UNION ALL
SELECT n+1, (n+1)*fact FROM temp -- Recursive Subquery
WHERE n < 9)
SELECT * FROM temp;
See also
- Datalog also implements fixpoint queries
- Deductive databases
- Hierarchical model
- Reachability
- Transitive closure
- Tree structure
References
<templatestyles src="Reflist/styles.css" />
Cite error: Invalid <references>
tag; parameter "group" is allowed only.
<references />
, or <references group="..." />
Further reading
- Lua error in package.lua at line 80: module 'strict' not found.
Academic textbooks. Note that these cover only the SQL:1999 standard (and Datalog), but not the Oracle extension.
- Lua error in package.lua at line 80: module 'strict' not found.
- Lua error in package.lua at line 80: module 'strict' not found. Chapter 24.
- Lua error in package.lua at line 80: module 'strict' not found.
External links
- http://stackoverflow.com/questions/1731889/cycle-detection-with-recursive-subquery-factoring
- http://explainextended.com/2009/11/18/sql-server-are-the-recursive-ctes-really-set-based/
- http://gennick.com/with.html
- http://www.cs.duke.edu/courses/fall04/cps116/lectures/11-recursion.pdf
- http://www.blacktdn.com.br/2015/06/blacktdn-mssql-usando-consulta-cte.html
- ↑ 1.0 1.1 Lua error in package.lua at line 80: module 'strict' not found.
- ↑ 2.0 2.1 Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found. PostgreSQL
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Paragon corporation: Using PostgreSQL User-Defined Functions to solve the Tree Problem, February 15, 2004, accessed September 19, 2015
- ↑ Hierarchical Queries, EnterpriseDB
- ↑ Hierarchical Queries, Oracle
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Hierarchical Clause, IBM Informix
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Comparison of relational database management systems#Database capabilities
- ↑ http://www.h2database.com/html/advanced.html#recursive_queries
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/topic/com.ibm.db2z9.doc.apsg/src/tpc/db2z_xmprecursivecte.htm
- ↑ http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=%2Fsqlp%2Frbafyrecursivequeries.htm
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.