Skip to content

Multi-use CTE's #5485

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions _includes/v19.2/known-limitations/cte-by-name.md

This file was deleted.

113 changes: 46 additions & 67 deletions _includes/v19.2/sql/diagrams/with_clause.html
Original file line number Diff line number Diff line change
@@ -1,71 +1,50 @@
<div><svg width="744" height="448">
<div><svg width="765" height="449">
<polygon points="9 17 1 13 1 21"></polygon>
<polygon points="17 17 9 13 9 21"></polygon>
<rect x="31" y="3" width="56" height="32" rx="10"></rect>
<rect x="29" y="1" width="56" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="39" y="21">WITH</text>
<a xlink:href="sql-grammar.html#table_alias_name" xlink:title="table_alias_name">
<rect x="45" y="157" width="124" height="32"></rect>
<rect x="43" y="155" width="124" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="53" y="175">table_alias_name</text>
</a>
<rect x="209" y="157" width="26" height="32" rx="10"></rect>
<rect x="207" y="155" width="26" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="217" y="175">(</text>
<a xlink:href="sql-grammar.html#name" xlink:title="name">
<rect x="275" y="157" width="54" height="32"></rect>
<rect x="273" y="155" width="54" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="283" y="175">name</text>
</a>
<rect x="275" y="113" width="24" height="32" rx="10"></rect>
<rect x="273" y="111" width="24" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="283" y="131">,</text>
<rect x="369" y="157" width="26" height="32" rx="10"></rect>
<rect x="367" y="155" width="26" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="377" y="175">)</text>
<rect x="435" y="157" width="38" height="32" rx="10"></rect>
<rect x="433" y="155" width="38" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="443" y="175">AS</text>
<rect x="493" y="157" width="26" height="32" rx="10"></rect>
<rect x="491" y="155" width="26" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="501" y="175">(</text>
<a xlink:href="sql-grammar.html#preparable_stmt" xlink:title="preparable_stmt">
<rect x="539" y="157" width="118" height="32"></rect>
<rect x="537" y="155" width="118" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="547" y="175">preparable_stmt</text>
</a>
<rect x="677" y="157" width="26" height="32" rx="10"></rect>
<rect x="675" y="155" width="26" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="685" y="175">)</text>
<rect x="31" y="3" width="58" height="32" rx="10"></rect>
<rect x="29" y="1" width="58" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="39" y="21">WITH</text><a xlink:href="sql-grammar.html#table_alias_name" xlink:title="table_alias_name">
<rect x="45" y="157" width="134" height="32"></rect>
<rect x="43" y="155" width="134" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="53" y="175">table_alias_name</text></a><rect x="219" y="157" width="26" height="32" rx="10"></rect>
<rect x="217" y="155" width="26" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="227" y="175">(</text><a xlink:href="sql-grammar.html#name" xlink:title="name">
<rect x="285" y="157" width="56" height="32"></rect>
<rect x="283" y="155" width="56" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="293" y="175">name</text></a><rect x="285" y="113" width="24" height="32" rx="10"></rect>
<rect x="283" y="111" width="24" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="293" y="131">,</text>
<rect x="381" y="157" width="26" height="32" rx="10"></rect>
<rect x="379" y="155" width="26" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="389" y="175">)</text>
<rect x="447" y="157" width="38" height="32" rx="10"></rect>
<rect x="445" y="155" width="38" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="455" y="175">AS</text>
<rect x="505" y="157" width="26" height="32" rx="10"></rect>
<rect x="503" y="155" width="26" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="513" y="175">(</text><a xlink:href="sql-grammar.html#preparable_stmt" xlink:title="preparable_stmt">
<rect x="551" y="157" width="126" height="32"></rect>
<rect x="549" y="155" width="126" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="559" y="175">preparable_stmt</text></a><rect x="697" y="157" width="26" height="32" rx="10"></rect>
<rect x="695" y="155" width="26" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="705" y="175">)</text>
<rect x="45" y="69" width="24" height="32" rx="10"></rect>
<rect x="43" y="67" width="24" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="53" y="87">,</text>
<a xlink:href="sql-grammar.html#insert_stmt" xlink:title="insert_stmt">
<rect x="601" y="239" width="88" height="32"></rect>
<rect x="599" y="237" width="88" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="609" y="257">insert_stmt</text>
</a>
<a xlink:href="sql-grammar.html#update_stmt" xlink:title="update_stmt">
<rect x="601" y="283" width="96" height="32"></rect>
<rect x="599" y="281" width="96" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="609" y="301">update_stmt</text>
</a>
<a xlink:href="sql-grammar.html#delete_stmt" xlink:title="delete_stmt">
<rect x="601" y="327" width="92" height="32"></rect>
<rect x="599" y="325" width="92" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="609" y="345">delete_stmt</text>
</a>
<a xlink:href="sql-grammar.html#upsert_stmt" xlink:title="upsert_stmt">
<rect x="601" y="371" width="94" height="32"></rect>
<rect x="599" y="369" width="94" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="609" y="389">upsert_stmt</text>
</a>
<a xlink:href="sql-grammar.html#select_stmt" xlink:title="select_stmt">
<rect x="601" y="415" width="90" height="32"></rect>
<rect x="599" y="413" width="90" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="609" y="433">select_stmt</text>
</a>
<path class="line" d="m17 17 h2 m0 0 h10 m56 0 h10 m2 0 l2 0 m2 0 l2 0 m2 0 l2 0 m-106 154 l2 0 m2 0 l2 0 m2 0 l2 0 m22 0 h10 m124 0 h10 m20 0 h10 m26 0 h10 m20 0 h10 m54 0 h10 m-94 0 l20 0 m-1 0 q-9 0 -9 -10 l0 -24 q0 -10 10 -10 m74 44 l20 0 m-20 0 q10 0 10 -10 l0 -24 q0 -10 -10 -10 m-74 0 h10 m24 0 h10 m0 0 h30 m20 44 h10 m26 0 h10 m-226 0 h20 m206 0 h20 m-246 0 q10 0 10 10 m226 0 q0 -10 10 -10 m-236 10 v14 m226 0 v-14 m-226 14 q0 10 10 10 m206 0 q10 0 10 -10 m-216 10 h10 m0 0 h196 m20 -34 h10 m38 0 h10 m0 0 h10 m26 0 h10 m0 0 h10 m118 0 h10 m0 0 h10 m26 0 h10 m-698 0 l20 0 m-1 0 q-9 0 -9 -10 l0 -68 q0 -10 10 -10 m678 88 l20 0 m-20 0 q10 0 10 -10 l0 -68 q0 -10 -10 -10 m-678 0 h10 m24 0 h10 m0 0 h634 m22 88 l2 0 m2 0 l2 0 m2 0 l2 0 m-186 82 l2 0 m2 0 l2 0 m2 0 l2 0 m22 0 h10 m88 0 h10 m0 0 h8 m-136 0 h20 m116 0 h20 m-156 0 q10 0 10 10 m136 0 q0 -10 10 -10 m-146 10 v24 m136 0 v-24 m-136 24 q0 10 10 10 m116 0 q10 0 10 -10 m-126 10 h10 m96 0 h10 m-126 -10 v20 m136 0 v-20 m-136 20 v24 m136 0 v-24 m-136 24 q0 10 10 10 m116 0 q10 0 10 -10 m-126 10 h10 m92 0 h10 m0 0 h4 m-126 -10 v20 m136 0 v-20 m-136 20 v24 m136 0 v-24 m-136 24 q0 10 10 10 m116 0 q10 0 10 -10 m-126 10 h10 m94 0 h10 m0 0 h2 m-126 -10 v20 m136 0 v-20 m-136 20 v24 m136 0 v-24 m-136 24 q0 10 10 10 m116 0 q10 0 10 -10 m-126 10 h10 m90 0 h10 m0 0 h6 m23 -176 h-3"></path>
<polygon points="735 253 743 249 743 257"></polygon>
<polygon points="735 253 727 249 727 257"></polygon>
</svg></div>
<text class="terminal" x="53" y="87">,</text><a xlink:href="sql-grammar.html#insert_stmt" xlink:title="insert_stmt">
<rect x="615" y="239" width="92" height="32"></rect>
<rect x="613" y="237" width="92" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="623" y="257">insert_stmt</text></a><a xlink:href="sql-grammar.html#update_stmt" xlink:title="update_stmt">
<rect x="615" y="283" width="102" height="32"></rect>
<rect x="613" y="281" width="102" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="623" y="301">update_stmt</text></a><a xlink:href="sql-grammar.html#delete_stmt" xlink:title="delete_stmt">
<rect x="615" y="327" width="96" height="32"></rect>
<rect x="613" y="325" width="96" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="623" y="345">delete_stmt</text></a><a xlink:href="sql-grammar.html#upsert_stmt" xlink:title="upsert_stmt">
<rect x="615" y="371" width="98" height="32"></rect>
<rect x="613" y="369" width="98" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="623" y="389">upsert_stmt</text></a><a xlink:href="sql-grammar.html#select_stmt" xlink:title="select_stmt">
<rect x="615" y="415" width="94" height="32"></rect>
<rect x="613" y="413" width="94" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="623" y="433">select_stmt</text></a><path class="line" d="m17 17 h2 m0 0 h10 m58 0 h10 m2 0 l2 0 m2 0 l2 0 m2 0 l2 0 m-108 154 l2 0 m2 0 l2 0 m2 0 l2 0 m22 0 h10 m134 0 h10 m20 0 h10 m26 0 h10 m20 0 h10 m56 0 h10 m-96 0 l20 0 m-1 0 q-9 0 -9 -10 l0 -24 q0 -10 10 -10 m76 44 l20 0 m-20 0 q10 0 10 -10 l0 -24 q0 -10 -10 -10 m-76 0 h10 m24 0 h10 m0 0 h32 m20 44 h10 m26 0 h10 m-228 0 h20 m208 0 h20 m-248 0 q10 0 10 10 m228 0 q0 -10 10 -10 m-238 10 v14 m228 0 v-14 m-228 14 q0 10 10 10 m208 0 q10 0 10 -10 m-218 10 h10 m0 0 h198 m20 -34 h10 m38 0 h10 m0 0 h10 m26 0 h10 m0 0 h10 m126 0 h10 m0 0 h10 m26 0 h10 m-718 0 l20 0 m-1 0 q-9 0 -9 -10 l0 -68 q0 -10 10 -10 m698 88 l20 0 m-20 0 q10 0 10 -10 l0 -68 q0 -10 -10 -10 m-698 0 h10 m24 0 h10 m0 0 h654 m22 88 l2 0 m2 0 l2 0 m2 0 l2 0 m-192 82 l2 0 m2 0 l2 0 m2 0 l2 0 m22 0 h10 m92 0 h10 m0 0 h10 m-142 0 h20 m122 0 h20 m-162 0 q10 0 10 10 m142 0 q0 -10 10 -10 m-152 10 v24 m142 0 v-24 m-142 24 q0 10 10 10 m122 0 q10 0 10 -10 m-132 10 h10 m102 0 h10 m-132 -10 v20 m142 0 v-20 m-142 20 v24 m142 0 v-24 m-142 24 q0 10 10 10 m122 0 q10 0 10 -10 m-132 10 h10 m96 0 h10 m0 0 h6 m-132 -10 v20 m142 0 v-20 m-142 20 v24 m142 0 v-24 m-142 24 q0 10 10 10 m122 0 q10 0 10 -10 m-132 10 h10 m98 0 h10 m0 0 h4 m-132 -10 v20 m142 0 v-20 m-142 20 v24 m142 0 v-24 m-142 24 q0 10 10 10 m122 0 q10 0 10 -10 m-132 10 h10 m94 0 h10 m0 0 h8 m23 -176 h-3"></path>
<polygon points="755 253 763 249 763 257"></polygon>
<polygon points="755 253 747 249 747 257"></polygon></svg></div>
111 changes: 66 additions & 45 deletions v19.2/common-table-expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ Parameter | Description

## Overview

{{site.data.alerts.callout_info}}
The examples on this page use MovR, a fictional vehicle-sharing application, to demonstrate CockroachDB SQL statements. To follow along, run [`cockroach demo`](cockroach-demo.html) from the command line to start a temporary, in-memory cluster with the `movr` dataset preloaded.

For more information about the MovR example application and dataset, see [MovR: A Global Vehicle-sharing App](movr.html).
{{site.data.alerts.end}}

A query or statement of the form `WITH x AS y IN z` creates the
temporary table name `x` for the results of the subquery `y`, to be
reused in the context of the query `z`.
Expand All @@ -39,24 +45,32 @@ For example:

{% include copy-clipboard.html %}
~~~ sql
> WITH o AS (SELECT * FROM orders WHERE id IN (33, 542, 112))
SELECT *
FROM customers AS c, o
WHERE o.customer_id = c.id;
> WITH r AS (SELECT * FROM rides WHERE revenue > 98)
SELECT * FROM users AS u, r WHERE r.rider_id = u.id;
~~~

In this example, the `WITH` clause defines the temporary name `o` for
the subquery over `orders`, and that name becomes a valid table name
~~~
id | city | name | address | credit_card | id | city | vehicle_city | rider_id | vehicle_id | start_address | end_address | start_time | end_time | revenue
+--------------------------------------+---------------+------------------+--------------------------------+-------------+--------------------------------------+---------------+---------------+--------------------------------------+--------------------------------------+-----------------------------------+---------------------------+---------------------------+---------------------------+---------+
ae147ae1-47ae-4800-8000-000000000022 | amsterdam | Tyler Dalton | 88194 Angela Gardens Suite 94 | 4443538758 | bbe76c8b-4395-4000-8000-00000000016f | amsterdam | amsterdam | ae147ae1-47ae-4800-8000-000000000022 | aaaaaaaa-aaaa-4800-8000-00000000000a | 45295 Brewer View Suite 52 | 62188 Jade Causeway | 2018-12-17 03:04:05+00:00 | 2018-12-17 13:04:05+00:00 | 99.00
c7ae147a-e147-4000-8000-000000000027 | paris | Tina Miller | 97521 Mark Extensions | 8880478663 | d5810624-dd2f-4800-8000-0000000001a1 | paris | paris | c7ae147a-e147-4000-8000-000000000027 | cccccccc-cccc-4000-8000-00000000000c | 47713 Reynolds Mountains Suite 39 | 1417 Stephanie Villages | 2018-12-17 03:04:05+00:00 | 2018-12-18 22:04:05+00:00 | 99.00
75c28f5c-28f5-4400-8000-000000000017 | san francisco | William Wood | 36021 Steven Cove Apt. 89 | 5669281259 | 8ac08312-6e97-4000-8000-00000000010f | san francisco | san francisco | 75c28f5c-28f5-4400-8000-000000000017 | 77777777-7777-4800-8000-000000000007 | 84407 Tony Crest | 55336 Jon Manors | 2018-12-10 03:04:05+00:00 | 2018-12-11 13:04:05+00:00 | 99.00
8a3d70a3-d70a-4000-8000-00000000001b | san francisco | Jessica Martinez | 96676 Jennifer Knolls Suite 91 | 1601930189 | 7d70a3d7-0a3d-4000-8000-0000000000f5 | san francisco | san francisco | 8a3d70a3-d70a-4000-8000-00000000001b | 77777777-7777-4800-8000-000000000007 | 78978 Stevens Ramp Suite 8 | 7340 Alison Field Apt. 44 | 2018-12-19 03:04:05+00:00 | 2018-12-21 10:04:05+00:00 | 99.00
47ae147a-e147-4000-8000-00000000000e | washington dc | Patricia Herrera | 80588 Perez Camp | 6812041796 | 4083126e-978d-4000-8000-00000000007e | washington dc | washington dc | 47ae147a-e147-4000-8000-00000000000e | 44444444-4444-4400-8000-000000000004 | 33055 Julie Dale Suite 93 | 17280 Jill Drives | 2019-01-01 03:04:05+00:00 | 2019-01-01 14:04:05+00:00 | 99.00
(5 rows)
~~~

In this example, the `WITH` clause defines the temporary name `r` for
the subquery over `rides`, and that name becomes a valid table name
for use in any [table expression](table-expressions.html) of the
subsequent `SELECT` clause.

This query is equivalent to, but arguably simpler to read than:

{% include copy-clipboard.html %}
~~~ sql
> SELECT *
FROM customers AS c, (SELECT * FROM orders WHERE id IN (33, 542, 112)) AS o
WHERE o.customer_id = c.id;
> SELECT * FROM users AS u, (SELECT * FROM rides WHERE revenue > 98) AS r
WHERE r.rider_id = u.id;
~~~

It is also possible to define multiple common table expressions
Expand All @@ -66,12 +80,12 @@ following query is equivalent to the two examples above:

{% include copy-clipboard.html %}
~~~ sql
> WITH o AS (SELECT * FROM orders WHERE id IN (33, 542, 112)),
results AS (SELECT * FROM customers AS c, o WHERE o.customer_id = c.id)
> WITH r AS (SELECT * FROM rides WHERE revenue > 98),
results AS (SELECT * FROM users AS u, r WHERE r.rider_id = u.id)
SELECT * FROM results;
~~~

In this example, the second CTE `results` refers to the first CTE `o`
In this example, the second CTE `results` refers to the first CTE `r`
by name. The final query refers to the CTE `results`.

## Nested `WITH` clauses
Expand All @@ -80,9 +94,10 @@ It is possible to use a `WITH` clause in a subquery, or even a `WITH` clause wit

{% include copy-clipboard.html %}
~~~ sql
> WITH a AS (SELECT * FROM (WITH b AS (SELECT * FROM c)
SELECT * FROM b))
SELECT * FROM a;
> WITH u AS
(SELECT * FROM
(WITH u_tab AS (SELECT * FROM users) SELECT * FROM u_tab))
SELECT * FROM u;
~~~

When analyzing [table expressions](table-expressions.html) that
Expand All @@ -91,41 +106,38 @@ closest to the table expression. For example:

{% include copy-clipboard.html %}
~~~ sql
> WITH a AS (TABLE x),
b AS (WITH a AS (TABLE y)
SELECT * FROM a)
SELECT * FROM b;
> WITH
u AS (SELECT * FROM users),
v AS (WITH u AS (SELECT * from vehicles) SELECT * FROM u)
SELECT * FROM v;
~~~

In this example, the inner subquery `SELECT * FROM a` will select from
table `y` (closest `WITH` clause), not from table `x`.
In this example, the inner subquery `SELECT * FROM v` will select from
table `vehicles` (closest `WITH` clause), not from table `users`.

## Data modifying statements

It is possible to use a data-modifying statement (`INSERT`, `DELETE`,
It is possible to use a [data-modifying statement](sql-statements.html#data-manipulation-statements) (`INSERT`, `DELETE`,
etc.) as a common table expression.

For example:

{% include copy-clipboard.html %}
~~~ sql
> WITH v AS (INSERT INTO t(x) VALUES (1), (2), (3) RETURNING x)
SELECT x+1 FROM v
> WITH final_code AS
(INSERT INTO promo_codes(code, description, rules)
VALUES ('half_off', 'Half-price ride!', '{"type": "percent_discount", "value": "50%"}'), ('free_ride', 'Free ride!', '{"type": "percent_discount", "value": "100%"}')
returning rules)
SELECT rules FROM final_code;
~~~

However, the following restriction applies: only `WITH` sub-clauses at
the top level of a SQL statement can contain data-modifying
statements. The example above is valid, but the following is not:

{% include copy-clipboard.html %}
~~~ sql
> SELECT x+1 FROM
(WITH v AS (INSERT INTO t(x) VALUES (1), (2), (3) RETURNING x)
SELECT * FROM v);
~~~

This is not valid because the `WITH` clause that defines an `INSERT`
common table expression is not at the top level of the query.
rules
+-----------------------------------------------+
{"type": "percent_discount", "value": "50%"}
{"type": "percent_discount", "value": "100%"}
(2 rows)
~~~

{{site.data.alerts.callout_info}}
If a common table expression contains
Expand All @@ -137,20 +149,29 @@ href="subqueries.html#data-writes-in-subqueries">Data
Writes in Subqueries</a> for details.
{{site.data.alerts.end}}

<div markdown="1"></div>
## Reusing common table expressions

## Known limitations
<span class="version-tag">New in v19.2:</span> You can reference a CTE multiple times in a single query, using a `WITH` operator.

{{site.data.alerts.callout_info}}
The following limitations may be lifted
in a future version of CockroachDB.
{{site.data.alerts.end}}
For example:

<div markdown="1"></div>
{% include copy-clipboard.html %}
~~~ sql
> WITH
users_ny AS (SELECT name, id FROM users WHERE city='new york'),
vehicles_ny AS (SELECT type, id, owner_id FROM vehicles WHERE city='new york')
SELECT * FROM users_ny JOIN vehicles_ny ON users_ny.id = vehicles_ny.owner_id;
~~~

### Referring to a CTE by name more than once
~~~
name | id | type | id | owner_id
+------------------+--------------------------------------+------------+--------------------------------------+--------------------------------------+
James Hamilton | 051eb851-eb85-4ec0-8000-000000000001 | skateboard | 00000000-0000-4000-8000-000000000000 | 051eb851-eb85-4ec0-8000-000000000001
Catherine Nelson | 147ae147-ae14-4b00-8000-000000000004 | scooter | 11111111-1111-4100-8000-000000000001 | 147ae147-ae14-4b00-8000-000000000004
(2 rows)
~~~

{% include {{ page.version.version }}/known-limitations/cte-by-name.md %}
In this single query, you define two CTE's and then reuse them in a table join.

## See also

Expand Down
Loading