diff --git a/doc/src/sgml/queries.sgml b/doc/src/sgml/queries.sgml index 42b6e06da3..e65dbb4c2f 100644 --- a/doc/src/sgml/queries.sgml +++ b/doc/src/sgml/queries.sgml @@ -1539,11 +1539,23 @@ SELECT select_list FROM table_expression - WITH provides a way to write subqueries for use in a larger - query. The subqueries, which are often referred to as Common Table - Expressions or CTEs, can be thought of as defining - temporary tables that exist just for this query. One use of this feature - is to break down complicated queries into simpler parts. An example is: + WITH provides a way to write auxiliary statements for use in a + larger query. These statements, which are often referred to as Common + Table Expressions or CTEs, can be thought of as defining + temporary tables that exist just for one query. Each auxiliary statement + in a WITH clause can be a SELECT, + INSERT, UPDATE, or DELETE; and the + WITH clause itself is attached to a primary statement that can + also be a SELECT, INSERT, UPDATE, or + DELETE. + + + + <command>SELECT</> in <literal>WITH</> + + + The basic value of SELECT in WITH is to + break down complicated queries into simpler parts. An example is: WITH regional_sales AS ( @@ -1565,6 +1577,11 @@ GROUP BY region, product; which displays per-product sales totals in only the top sales regions. + The WITH clause defines two auxiliary statements named + regional_sales and top_regions, + where the output of regional_sales is used in + top_regions and the output of top_regions + is used in the primary SELECT query. This example could have been written without WITH, but we'd have needed two levels of nested sub-SELECTs. It's a bit easier to follow this way. @@ -1779,7 +1796,9 @@ SELECT n FROM t LIMIT 100; fetched by the parent query. Using this trick in production is not recommended, because other systems might work differently. Also, it usually won't work if you make the outer query sort the recursive query's - results or join them to some other table. + results or join them to some other table, because in such cases the + outer query will usually try to fetch all of the WITH query's + output anyway. @@ -1806,6 +1825,152 @@ SELECT n FROM t LIMIT 100; In each case it effectively provides temporary table(s) that can be referred to in the main command. + + + + Data-Modifying Statements in <literal>WITH</> + + + You can use data-modifying statements (INSERT, + UPDATE, or DELETE) in WITH. This + allows you to perform several different operations in the same query. + An example is: + + +WITH moved_rows AS ( + DELETE FROM products + WHERE + "date" >= '2010-10-01' AND + "date" < '2010-11-01' + RETURNING * +) +INSERT INTO products_log +SELECT * FROM moved_rows; + + + This query effectively moves rows from products to + products_log. The DELETE in WITH + deletes the specified rows from products, returning their + contents by means of its RETURNING clause; and then the + primary query reads that output and inserts it into + products_log. + + + + A fine point of the above example is that the WITH clause is + attached to the INSERT, not the sub-SELECT within + the INSERT. This is necessary because data-modifying + statements are only allowed in WITH clauses that are attached + to the top-level statement. However, normal WITH visibility + rules apply, so it is possible to refer to the WITH + statement's output from the sub-SELECT. + + + + Data-modifying statements in WITH usually have + RETURNING clauses, as seen in the example above. + It is the output of the RETURNING clause, not the + target table of the data-modifying statement, that forms the temporary + table that can be referred to by the rest of the query. If a + data-modifying statement in WITH lacks a RETURNING + clause, then it forms no temporary table and cannot be referred to in + the rest of the query. Such a statement will be executed nonetheless. + A not-particularly-useful example is: + + +WITH t AS ( + DELETE FROM foo +) +DELETE FROM bar; + + + This example would remove all rows from tables foo and + bar. The number of affected rows reported to the client + would only include rows removed from bar. + + + + Recursive self-references in data-modifying statements are not + allowed. In some cases it is possible to work around this limitation by + referring to the output of a recursive WITH, for example: + + +WITH RECURSIVE included_parts(sub_part, part) AS ( + SELECT sub_part, part FROM parts WHERE part = 'our_product' + UNION ALL + SELECT p.sub_part, p.part + FROM included_parts pr, parts p + WHERE p.part = pr.sub_part + ) +DELETE FROM parts + WHERE part IN (SELECT part FROM included_parts); + + + This query would remove all direct and indirect subparts of a product. + + + + Data-modifying statements in WITH are executed exactly once, + and always to completion, independently of whether the primary query + reads all (or indeed any) of their output. Notice that this is different + from the rule for SELECT in WITH: as stated in the + previous section, execution of a SELECT is carried only as far + as the primary query demands its output. + + + + The sub-statements in WITH are executed concurrently with + each other and with the main query. Therefore, when using data-modifying + statements in WITH, the order in which the specified updates + actually happen is unpredictable. All the statements are executed with + the same snapshot (see ), so they + cannot see each others' effects on the target tables. This + alleviates the effects of the unpredictability of the actual order of row + updates, and means that RETURNING data is the only way to + communicate changes between different WITH sub-statements and + the main query. An example of this is that in + + +WITH t AS ( + UPDATE products SET price = price * 1.05 + RETURNING * +) +SELECT * FROM products; + + + the outer SELECT would return the original prices before the + action of the UPDATE, while in + + +WITH t AS ( + UPDATE products SET price = price * 1.05 + RETURNING * +) +SELECT * FROM t; + + + the outer SELECT would return the updated data. + + + + Trying to update the same row twice in a single statement is not + supported. Only one of the modifications takes place, but it is not easy + (and sometimes not possible) to reliably predict which one. This also + applies to deleting a row that was already updated in the same statement: + only the update is performed. Therefore you should generally avoid trying + to modify a single row twice in a single statement. In particular avoid + writing WITH sub-statements that could affect the same rows + changed by the main statement or a sibling sub-statement. The effects + of such a statement will not be predictable. + + + + At present, any table used as the target of a data-modifying statement in + WITH must not have a conditional rule, nor an ALSO + rule, nor an INSTEAD rule that expands to multiple statements. + + + diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml index 92e47d1279..8bf7a06022 100644 --- a/doc/src/sgml/ref/select.sgml +++ b/doc/src/sgml/ref/select.sgml @@ -58,9 +58,9 @@ SELECT [ ALL | DISTINCT [ ON ( expressionand with_query is: - with_query_name [ ( column_name [, ...] ) ] AS ( select ) + with_query_name [ ( column_name [, ...] ) ] AS ( select | insert | update | delete ) -TABLE { [ ONLY ] table_name [ * ] | with_query_name } +TABLE [ ONLY ] table_name [ * ] @@ -209,6 +209,17 @@ TABLE { [ ONLY ] table_name [ * ] | subqueries that can be referenced by name in the primary query. The subqueries effectively act as temporary tables or views for the duration of the primary query. + Each subquery can be a SELECT, + INSERT, UPDATE or + DELETE statement. + When writing a data-modifying statement (INSERT, + UPDATE or DELETE) in + WITH, it is usual to include a RETURNING clause. + It is the output of RETURNING, not the underlying + table that the statement modifies, that forms the temporary table that is + read by the primary query. If RETURNING is omitted, the + statement is still executed, but it produces no output so it cannot be + referenced as a table by the primary query. @@ -220,14 +231,18 @@ TABLE { [ ONLY ] table_name [ * ] | If RECURSIVE is specified, it allows a - subquery to reference itself by name. Such a subquery must have - the form + SELECT subquery to reference itself by name. Such a + subquery must have the form non_recursive_term UNION [ ALL | DISTINCT ] recursive_term where the recursive self-reference must appear on the right-hand side of the UNION. Only one recursive self-reference - is permitted per query. + is permitted per query. Recursive data-modifying statements are not + supported, but you can use the results of a recursive + SELECT query in + a data-modifying statement. See for + an example. @@ -241,9 +256,21 @@ TABLE { [ ONLY ] table_name [ * ] | - A useful property of WITH queries is that they + A key property of WITH queries is that they are evaluated only once per execution of the primary query, even if the primary query refers to them more than once. + In particular, data-modifying statements are guaranteed to be + executed once and only once, regardless of whether the primary query + reads all or any of their output. + + + + The primary query and the WITH queries are all + (notionally) executed at the same time. This implies that the effects of + a data-modifying statement in WITH cannot be seen from + other parts of the query, other than by reading its RETURNING + output. If two such data-modifying statements attempt to modify the same + row, the results are unspecified. @@ -1657,6 +1684,16 @@ SELECT distributors.* WHERE distributors.name = 'Westward'; + + Data-Modifying Statements in <literal>WITH</> + + + PostgreSQL allows INSERT, + UPDATE, and DELETE to be used as WITH + queries. This is not found in the SQL standard. + + + Nonstandard Clauses