A common table expression (CTE) is a named temporary result set that exists within the scope of a single statement and that can be referred to later within that statement, possibly multiple times.
1 With
This tag allows you to do WITH ... AS operations independent of the DBMS.
<with recursive='true|false'>
<as
name='name'
params='params'
> +
<select /> *
<union /> *
</as>
</with>
Attributes | |||||
---|---|---|---|---|---|
Name | Type | Required | Default | Description | |
Arecursive | string | false | Indicates whether there is any recursive CTE. |
Arguments | |||||
---|---|---|---|---|---|
Name | Type | Required | Unique | Nullable | Description |
Eas | Defines a new table expression. | ||||
Aname | string | The table expression name. | |||
Aparams | string | Define the CTE column names. If not declared, they are implied by the select. This attribute is necessary for recursive CTEs. | |||
Eselect | Select statement. | ||||
Eunion | Union statement. |
Example
Copy
<with> <as name="cte1"> <select> <columns> a1 </columns> <from table="master_table"/> </select> </as> <select> <columns> a1 </columns> <from table="cte1"/> </select> </with>
Copy
WITH cte1 AS ( SELECT a1 FROM master_table ) SELECT a1 FROM cte1
2 Multiple CTEs
More than one common table expression can be defined to be used in the following statement (select or union).
Example
Copy
<with> <as name="cte1"> <select> <columns> a1 </columns> <from table="master_table_1"/> </select> </as> <as name="cte2"> <select> <columns> a1 </columns> <from table="master_table_2"/> </select> </as> <select> <columns> cte1.a1 </columns> <from table="cte1"> <join table="cte2"> <on>cte1.a1 = cte2.a1</on> </join> </from> </select> </with>
Copy
WITH cte1 AS ( SELECT a1 FROM master_table_1 ), cte2 AS ( SELECT a1 FROM master_table_2 ) SELECT cte1.a1 FROM cte1, cte2 WHERE cte1.a1 = cte2.a1
3 Recursivity
Recursivity can also be used with common table expressions. If there is any recursive CTE, recursive
must be set to true in the with
tag, and the parameters must be set in params
in the corresponding as
tag.
Example
Copy
<with recursive="true"> <as name="cte1" params="n, fact"> <union> <select-one> <columns> 0, 1 </columns> </select-one> <select> <columns> n+1, (n+1)*fact </columns> <from table="cte1"/> <where>n < 9</where> </select> </union> </as> <select> <columns> n, fact </columns> <from table="cte1"/> </select> </with>
Copy
WITH cte1(n, fact) AS ( SELECT 0, 1 FROM systables WHERE tabname = 'systables' UNION ALL SELECT n+1, (n+1)*fact FROM cte1 WHERE n < 9 ) SELECT n, fact FROM cte1
+-----------+-----------+
|n |fact |
|decimal(11,|decimal(21,|
|0) |0) |
+-----------+-----------+
|0 |1 |
|1 |1 |
|2 |2 |
|3 |6 |
|4 |24 |
|5 |120 |
|6 |720 |
|7 |5.040 |
|8 |40.320 |
|9 |362.880 |
+-----------+-----------+
4 Multiple and recursive
Multiple CTEs, some of them being recursive, can also be created.
Example
Copy
<with recursive="true"> <as name="cte1" params="n, fact"> <union> <select-one> <columns> 0, 1 </columns> </select-one> <select> <columns> n+1, (n+1)*fact </columns> <from table="cte1"/> <where>n < 9</where> </select> </union> </as> <as name="cte2"> <select> <columns> a1 </columns> <from table="master_table"/> </select> </as> <select> <columns> a1, n, fact </columns> <from table="cte1, cte2"/> </select> </with>
Copy
WITH cte1(n, fact) AS ( SELECT 0, 1 FROM systables WHERE tabname = 'systables' UNION ALL SELECT n+1, (n+1)*fact FROM cte1 WHERE n < 9 ) , cte2 AS ( SELECT a1 FROM master_table ) SELECT a1, n, fact FROM cte1, cte2
5 Usefulness example
One of the biggest advantages of CTEs is to avoid code duplication, thus making the code more readable. In the following example the repetition of the CASE WHEN
is avoided.
Example
Copy
<with> <as> <select> <column> film_id, title, (CASE WHEN length < 30 THEN 'Short' WHEN length < 90 THEN 'Medium' ELSE 'Long' END) length </column> <from table="film"/> </select> </as> <select> <column> film_id, title, length </column> <from table="cte_film"/> </select> </with>
Copy
WITH AS ( SELECT film_id, title, (CASE WHEN length < 30 THEN 'Short' WHEN length < 90 THEN 'Medium' ELSE 'Long' END) length FROM film ) SELECT film_id, title, length FROM cte_film WHERE length = 'Long'