Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c649fa2

Browse files
committed
Add RETURNING support to MERGE.
This allows a RETURNING clause to be appended to a MERGE query, to return values based on each row inserted, updated, or deleted. As with plain INSERT, UPDATE, and DELETE commands, the returned values are based on the new contents of the target table for INSERT and UPDATE actions, and on its old contents for DELETE actions. Values from the source relation may also be returned. As with INSERT/UPDATE/DELETE, the output of MERGE ... RETURNING may be used as the source relation for other operations such as WITH queries and COPY commands. Additionally, a special function merge_action() is provided, which returns 'INSERT', 'UPDATE', or 'DELETE', depending on the action executed for each row. The merge_action() function can be used anywhere in the RETURNING list, including in arbitrary expressions and subqueries, but it is an error to use it anywhere outside of a MERGE query's RETURNING list. Dean Rasheed, reviewed by Isaac Morland, Vik Fearing, Alvaro Herrera, Gurjeet Singh, Jian He, Jeff Davis, Merlin Moncure, Peter Eisentraut, and Wolfgang Walther. Discussion: http://postgr.es/m/CAEZATCWePEGQR5LBn-vD6SfeLZafzEm2Qy_L_Oky2=qw2w3Pzg@mail.gmail.com
1 parent 6a004f1 commit c649fa2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1198
-216
lines changed

doc/src/sgml/dml.sgml

+21-1
Original file line numberDiff line numberDiff line change
@@ -283,10 +283,15 @@ DELETE FROM products;
283283
<secondary>RETURNING</secondary>
284284
</indexterm>
285285

286+
<indexterm zone="dml-returning">
287+
<primary>MERGE</primary>
288+
<secondary>RETURNING</secondary>
289+
</indexterm>
290+
286291
<para>
287292
Sometimes it is useful to obtain data from modified rows while they are
288293
being manipulated. The <command>INSERT</command>, <command>UPDATE</command>,
289-
and <command>DELETE</command> commands all have an
294+
<command>DELETE</command>, and <command>MERGE</command> commands all have an
290295
optional <literal>RETURNING</literal> clause that supports this. Use
291296
of <literal>RETURNING</literal> avoids performing an extra database query to
292297
collect the data, and is especially valuable when it would otherwise be
@@ -339,6 +344,21 @@ DELETE FROM products
339344
</programlisting>
340345
</para>
341346

347+
<para>
348+
In a <command>MERGE</command>, the data available to <literal>RETURNING</literal> is
349+
the content of the source row plus the content of the inserted, updated, or
350+
deleted target row. Since it is quite common for the source and target to
351+
have many of the same columns, specifying <literal>RETURNING *</literal>
352+
can lead to a lot of duplicated columns, so it is often more useful to
353+
qualify it so as to return just the source or target row. For example:
354+
<programlisting>
355+
MERGE INTO products p USING new_products n ON p.product_no = n.product_no
356+
WHEN NOT MATCHED THEN INSERT VALUES (n.product_no, n.name, n.price)
357+
WHEN MATCHED THEN UPDATE SET name = n.name, price = n.price
358+
RETURNING p.*;
359+
</programlisting>
360+
</para>
361+
342362
<para>
343363
If there are triggers (<xref linkend="triggers"/>) on the target table,
344364
the data available to <literal>RETURNING</literal> is the row as modified by

doc/src/sgml/func.sgml

+79
Original file line numberDiff line numberDiff line change
@@ -22421,6 +22421,85 @@ SELECT count(*) FROM sometable;
2242122421

2242222422
</sect1>
2242322423

22424+
<sect1 id="functions-merge-support">
22425+
<title>Merge Support Functions</title>
22426+
22427+
<indexterm>
22428+
<primary>MERGE</primary>
22429+
<secondary>RETURNING</secondary>
22430+
</indexterm>
22431+
22432+
<para>
22433+
<productname>PostgreSQL</productname> includes one merge support function
22434+
that may be used in the <literal>RETURNING</literal> list of a
22435+
<xref linkend="sql-merge"/> command to identify the action taken for each
22436+
row.
22437+
</para>
22438+
22439+
<table id="functions-merge-support-table">
22440+
<title>Merge Support Functions</title>
22441+
22442+
<tgroup cols="1">
22443+
<thead>
22444+
<row>
22445+
<entry role="func_table_entry"><para role="func_signature">
22446+
Function
22447+
</para>
22448+
<para>
22449+
Description
22450+
</para></entry>
22451+
</row>
22452+
</thead>
22453+
22454+
<tbody>
22455+
<row>
22456+
<entry role="func_table_entry"><para role="func_signature">
22457+
<indexterm>
22458+
<primary>merge_action</primary>
22459+
</indexterm>
22460+
<function id="merge_action">merge_action</function> ( )
22461+
<returnvalue>text</returnvalue>
22462+
</para>
22463+
<para>
22464+
Returns the merge action command executed for the current row. This
22465+
will be <literal>'INSERT'</literal>, <literal>'UPDATE'</literal>, or
22466+
<literal>'DELETE'</literal>.
22467+
</para></entry>
22468+
</row>
22469+
</tbody>
22470+
</tgroup>
22471+
</table>
22472+
22473+
<para>
22474+
Example:
22475+
<screen><![CDATA[
22476+
MERGE INTO products p
22477+
USING stock s ON p.product_id = s.product_id
22478+
WHEN MATCHED AND s.quantity > 0 THEN
22479+
UPDATE SET in_stock = true, quantity = s.quantity
22480+
WHEN MATCHED THEN
22481+
UPDATE SET in_stock = false, quantity = 0
22482+
WHEN NOT MATCHED THEN
22483+
INSERT (product_id, in_stock, quantity)
22484+
VALUES (s.product_id, true, s.quantity)
22485+
RETURNING merge_action(), p.*;
22486+
22487+
merge_action | product_id | in_stock | quantity
22488+
--------------+------------+----------+----------
22489+
UPDATE | 1001 | t | 50
22490+
UPDATE | 1002 | f | 0
22491+
INSERT | 1003 | t | 10
22492+
]]></screen>
22493+
</para>
22494+
22495+
<para>
22496+
Note that this function can only be used in the <literal>RETURNING</literal>
22497+
list of a <command>MERGE</command> command. It is an error to use it in any
22498+
other part of a query.
22499+
</para>
22500+
22501+
</sect1>
22502+
2242422503
<sect1 id="functions-subquery">
2242522504
<title>Subquery Expressions</title>
2242622505

doc/src/sgml/glossary.sgml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1442,9 +1442,9 @@
14421442
to a <glossterm linkend="glossary-client">client</glossterm> upon the
14431443
completion of an <acronym>SQL</acronym> command, usually a
14441444
<command>SELECT</command> but it can be an
1445-
<command>INSERT</command>, <command>UPDATE</command>, or
1446-
<command>DELETE</command> command if the <literal>RETURNING</literal>
1447-
clause is specified.
1445+
<command>INSERT</command>, <command>UPDATE</command>,
1446+
<command>DELETE</command>, or <command>MERGE</command> command if the
1447+
<literal>RETURNING</literal> clause is specified.
14481448
</para>
14491449
<para>
14501450
The fact that a result set is a relation means that a query can be used

doc/src/sgml/plpgsql.sgml

+9-7
Original file line numberDiff line numberDiff line change
@@ -1043,8 +1043,8 @@ INSERT INTO mytable VALUES (1,'one'), (2,'two');
10431043
</para>
10441044

10451045
<para>
1046-
If the command does return rows (for example <command>SELECT</command>,
1047-
or <command>INSERT</command>/<command>UPDATE</command>/<command>DELETE</command>
1046+
If the command does return rows (for example <command>SELECT</command>, or
1047+
<command>INSERT</command>/<command>UPDATE</command>/<command>DELETE</command>/<command>MERGE</command>
10481048
with <literal>RETURNING</literal>), there are two ways to proceed.
10491049
When the command will return at most one row, or you only care about
10501050
the first row of output, write the command as usual but add
@@ -1172,6 +1172,7 @@ SELECT <replaceable>select_expressions</replaceable> INTO <optional>STRICT</opti
11721172
INSERT ... RETURNING <replaceable>expressions</replaceable> INTO <optional>STRICT</optional> <replaceable>target</replaceable>;
11731173
UPDATE ... RETURNING <replaceable>expressions</replaceable> INTO <optional>STRICT</optional> <replaceable>target</replaceable>;
11741174
DELETE ... RETURNING <replaceable>expressions</replaceable> INTO <optional>STRICT</optional> <replaceable>target</replaceable>;
1175+
MERGE ... RETURNING <replaceable>expressions</replaceable> INTO <optional>STRICT</optional> <replaceable>target</replaceable>;
11751176
</synopsis>
11761177

11771178
where <replaceable>target</replaceable> can be a record variable, a row
@@ -1182,8 +1183,8 @@ DELETE ... RETURNING <replaceable>expressions</replaceable> INTO <optional>STRIC
11821183
<literal>INTO</literal> clause) just as described above,
11831184
and the plan is cached in the same way.
11841185
This works for <command>SELECT</command>,
1185-
<command>INSERT</command>/<command>UPDATE</command>/<command>DELETE</command> with
1186-
<literal>RETURNING</literal>, and certain utility commands
1186+
<command>INSERT</command>/<command>UPDATE</command>/<command>DELETE</command>/<command>MERGE</command>
1187+
with <literal>RETURNING</literal>, and certain utility commands
11871188
that return row sets, such as <command>EXPLAIN</command>.
11881189
Except for the <literal>INTO</literal> clause, the SQL command is the same
11891190
as it would be written outside <application>PL/pgSQL</application>.
@@ -1259,7 +1260,7 @@ END;
12591260
</para>
12601261

12611262
<para>
1262-
For <command>INSERT</command>/<command>UPDATE</command>/<command>DELETE</command> with
1263+
For <command>INSERT</command>/<command>UPDATE</command>/<command>DELETE</command>/<command>MERGE</command> with
12631264
<literal>RETURNING</literal>, <application>PL/pgSQL</application> reports
12641265
an error for more than one returned row, even when
12651266
<literal>STRICT</literal> is not specified. This is because there
@@ -2657,8 +2658,9 @@ $$ LANGUAGE plpgsql;
26572658
The <replaceable>query</replaceable> used in this type of <literal>FOR</literal>
26582659
statement can be any SQL command that returns rows to the caller:
26592660
<command>SELECT</command> is the most common case,
2660-
but you can also use <command>INSERT</command>, <command>UPDATE</command>, or
2661-
<command>DELETE</command> with a <literal>RETURNING</literal> clause. Some utility
2661+
but you can also use <command>INSERT</command>, <command>UPDATE</command>,
2662+
<command>DELETE</command>, or <command>MERGE</command> with a
2663+
<literal>RETURNING</literal> clause. Some utility
26622664
commands such as <command>EXPLAIN</command> will work too.
26632665
</para>
26642666

doc/src/sgml/queries.sgml

+5-4
Original file line numberDiff line numberDiff line change
@@ -2063,9 +2063,10 @@ SELECT <replaceable>select_list</replaceable> FROM <replaceable>table_expression
20632063
Table Expressions or <acronym>CTE</acronym>s, can be thought of as defining
20642064
temporary tables that exist just for one query. Each auxiliary statement
20652065
in a <literal>WITH</literal> clause can be a <command>SELECT</command>,
2066-
<command>INSERT</command>, <command>UPDATE</command>, or <command>DELETE</command>; and the
2066+
<command>INSERT</command>, <command>UPDATE</command>, <command>DELETE</command>,
2067+
or <command>MERGE</command>; and the
20672068
<literal>WITH</literal> clause itself is attached to a primary statement that can
2068-
be a <command>SELECT</command>, <command>INSERT</command>, <command>UPDATE</command>,
2069+
also be a <command>SELECT</command>, <command>INSERT</command>, <command>UPDATE</command>,
20692070
<command>DELETE</command>, or <command>MERGE</command>.
20702071
</para>
20712072

@@ -2599,8 +2600,8 @@ SELECT * FROM w AS w1 JOIN w AS w2 ON w1.f = w2.f;
25992600
<title>Data-Modifying Statements in <literal>WITH</literal></title>
26002601

26012602
<para>
2602-
You can use most data-modifying statements (<command>INSERT</command>,
2603-
<command>UPDATE</command>, or <command>DELETE</command>, but not
2603+
You can use data-modifying statements (<command>INSERT</command>,
2604+
<command>UPDATE</command>, <command>DELETE</command>, or
26042605
<command>MERGE</command>) in <literal>WITH</literal>. This
26052606
allows you to perform several different operations in the same query.
26062607
An example is:

doc/src/sgml/ref/copy.sgml

+11-8
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,19 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
130130
A <link linkend="sql-select"><command>SELECT</command></link>,
131131
<link linkend="sql-values"><command>VALUES</command></link>,
132132
<link linkend="sql-insert"><command>INSERT</command></link>,
133-
<link linkend="sql-update"><command>UPDATE</command></link>, or
134-
<link linkend="sql-delete"><command>DELETE</command></link> command whose results are to be
135-
copied. Note that parentheses are required around the query.
133+
<link linkend="sql-update"><command>UPDATE</command></link>,
134+
<link linkend="sql-delete"><command>DELETE</command></link>, or
135+
<link linkend="sql-merge"><command>MERGE</command></link> command
136+
whose results are to be copied. Note that parentheses are required
137+
around the query.
136138
</para>
137139
<para>
138-
For <command>INSERT</command>, <command>UPDATE</command> and
139-
<command>DELETE</command> queries a <literal>RETURNING</literal> clause
140-
must be provided, and the target relation must not have a conditional
141-
rule, nor an <literal>ALSO</literal> rule, nor an
142-
<literal>INSTEAD</literal> rule that expands to multiple statements.
140+
For <command>INSERT</command>, <command>UPDATE</command>,
141+
<command>DELETE</command>, and <command>MERGE</command> queries a
142+
<literal>RETURNING</literal> clause must be provided, and the target
143+
relation must not have a conditional rule, nor an
144+
<literal>ALSO</literal> rule, nor an <literal>INSTEAD</literal> rule
145+
that expands to multiple statements.
143146
</para>
144147
</listitem>
145148
</varlistentry>

doc/src/sgml/ref/merge.sgml

+57-11
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ PostgreSQL documentation
2525
MERGE INTO [ ONLY ] <replaceable class="parameter">target_table_name</replaceable> [ * ] [ [ AS ] <replaceable class="parameter">target_alias</replaceable> ]
2626
USING <replaceable class="parameter">data_source</replaceable> ON <replaceable class="parameter">join_condition</replaceable>
2727
<replaceable class="parameter">when_clause</replaceable> [...]
28+
[ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ [ AS ] <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
2829

2930
<phrase>where <replaceable class="parameter">data_source</replaceable> is:</phrase>
3031

@@ -96,6 +97,18 @@ DELETE
9697
more fine-grained handling.
9798
</para>
9899

100+
<para>
101+
The optional <literal>RETURNING</literal> clause causes <command>MERGE</command>
102+
to compute and return value(s) based on each row inserted, updated, or
103+
deleted. Any expression using the source or target table's columns, or
104+
the <xref linkend="merge_action"/> function can be computed. When an
105+
<command>INSERT</command> or <command>UPDATE</command> action is performed,
106+
the new values of the target table's columns are used. When a
107+
<command>DELETE</command> is performed, the old values of the target table's
108+
columns are used. The syntax of the <literal>RETURNING</literal> list is
109+
identical to that of the output list of <command>SELECT</command>.
110+
</para>
111+
99112
<para>
100113
There is no separate <literal>MERGE</literal> privilege.
101114
If you specify an update action, you must have the
@@ -442,6 +455,36 @@ DELETE
442455
</listitem>
443456
</varlistentry>
444457

458+
<varlistentry>
459+
<term><replaceable class="parameter">output_expression</replaceable></term>
460+
<listitem>
461+
<para>
462+
An expression to be computed and returned by the <command>MERGE</command>
463+
command after each row is changed (whether inserted, updated, or deleted).
464+
The expression can use any columns of the source or target tables, or the
465+
<xref linkend="merge_action"/> function to return additional information
466+
about the action executed.
467+
</para>
468+
<para>
469+
Writing <literal>*</literal> will return all columns from the source
470+
table, followed by all columns from the target table. Often this will
471+
lead to a lot of duplication, since it is common for the source and
472+
target tables to have a lot of the same columns. This can be avoided by
473+
qualifying the <literal>*</literal> with the name or alias of the source
474+
or target table.
475+
</para>
476+
</listitem>
477+
</varlistentry>
478+
479+
<varlistentry>
480+
<term><replaceable class="parameter">output_name</replaceable></term>
481+
<listitem>
482+
<para>
483+
A name to use for a returned column.
484+
</para>
485+
</listitem>
486+
</varlistentry>
487+
445488
</variablelist>
446489
</refsect1>
447490

@@ -460,6 +503,13 @@ MERGE <replaceable class="parameter">total_count</replaceable>
460503
were changed in any way.
461504
</para>
462505

506+
<para>
507+
If the <command>MERGE</command> command contains a <literal>RETURNING</literal>
508+
clause, the result will be similar to that of a <command>SELECT</command>
509+
statement containing the columns and values defined in the
510+
<literal>RETURNING</literal> list, computed over the row(s) inserted, updated,
511+
or deleted by the command.
512+
</para>
463513
</refsect1>
464514

465515
<refsect1>
@@ -579,13 +629,6 @@ MERGE <replaceable class="parameter">total_count</replaceable>
579629
needed to avoid deadlocks between concurrent transactions.
580630
</para>
581631

582-
<para>
583-
There is no <literal>RETURNING</literal> clause with
584-
<command>MERGE</command>. Actions of <command>INSERT</command>,
585-
<command>UPDATE</command> and <command>DELETE</command> cannot contain
586-
<literal>RETURNING</literal> or <literal>WITH</literal> clauses.
587-
</para>
588-
589632
<para>
590633
When <command>MERGE</command> is run concurrently with other commands
591634
that modify the target table, the usual transaction isolation rules
@@ -638,7 +681,8 @@ WHEN NOT MATCHED THEN
638681
<para>
639682
Attempt to insert a new stock item along with the quantity of stock. If
640683
the item already exists, instead update the stock count of the existing
641-
item. Don't allow entries that have zero stock.
684+
item. Don't allow entries that have zero stock. Return details of all
685+
changes made.
642686
<programlisting>
643687
MERGE INTO wines w
644688
USING wine_stock_changes s
@@ -648,7 +692,8 @@ WHEN NOT MATCHED AND s.stock_delta > 0 THEN
648692
WHEN MATCHED AND w.stock + s.stock_delta > 0 THEN
649693
UPDATE SET stock = w.stock + s.stock_delta
650694
WHEN MATCHED THEN
651-
DELETE;
695+
DELETE
696+
RETURNING merge_action(), w.*;
652697
</programlisting>
653698

654699
The <literal>wine_stock_changes</literal> table might be, for example, a
@@ -663,8 +708,9 @@ WHEN MATCHED THEN
663708
This command conforms to the <acronym>SQL</acronym> standard.
664709
</para>
665710
<para>
666-
The <literal>WITH</literal> clause and <literal>DO NOTHING</literal>
667-
action are extensions to the <acronym>SQL</acronym> standard.
711+
The <literal>WITH</literal> clause, <literal>DO NOTHING</literal> action,
712+
and <literal>RETURNING</literal> clause are extensions to the
713+
<acronym>SQL</acronym> standard.
668714
</para>
669715
</refsect1>
670716
</refentry>

doc/src/sgml/ref/select.sgml

+6-5
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="parameter">expression</replac
7474

7575
<phrase>and <replaceable class="parameter">with_query</replaceable> is:</phrase>
7676

77-
<replaceable class="parameter">with_query_name</replaceable> [ ( <replaceable class="parameter">column_name</replaceable> [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( <replaceable class="parameter">select</replaceable> | <replaceable class="parameter">values</replaceable> | <replaceable class="parameter">insert</replaceable> | <replaceable class="parameter">update</replaceable> | <replaceable class="parameter">delete</replaceable> )
77+
<replaceable class="parameter">with_query_name</replaceable> [ ( <replaceable class="parameter">column_name</replaceable> [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( <replaceable class="parameter">select</replaceable> | <replaceable class="parameter">values</replaceable> | <replaceable class="parameter">insert</replaceable> | <replaceable class="parameter">update</replaceable> | <replaceable class="parameter">delete</replaceable> | <replaceable class="parameter">merge</replaceable> )
7878
[ SEARCH { BREADTH | DEPTH } FIRST BY <replaceable>column_name</replaceable> [, ...] SET <replaceable>search_seq_col_name</replaceable> ]
7979
[ CYCLE <replaceable>column_name</replaceable> [, ...] SET <replaceable>cycle_mark_col_name</replaceable> [ TO <replaceable>cycle_mark_value</replaceable> DEFAULT <replaceable>cycle_mark_default</replaceable> ] USING <replaceable>cycle_path_col_name</replaceable> ]
8080

@@ -230,10 +230,10 @@ TABLE [ ONLY ] <replaceable class="parameter">table_name</replaceable> [ * ]
230230
The subqueries effectively act as temporary tables or views
231231
for the duration of the primary query.
232232
Each subquery can be a <command>SELECT</command>, <command>TABLE</command>, <command>VALUES</command>,
233-
<command>INSERT</command>, <command>UPDATE</command> or
234-
<command>DELETE</command> statement.
233+
<command>INSERT</command>, <command>UPDATE</command>,
234+
<command>DELETE</command>, or <command>MERGE</command> statement.
235235
When writing a data-modifying statement (<command>INSERT</command>,
236-
<command>UPDATE</command> or <command>DELETE</command>) in
236+
<command>UPDATE</command>, <command>DELETE</command>, or <command>MERGE</command>) in
237237
<literal>WITH</literal>, it is usual to include a <literal>RETURNING</literal> clause.
238238
It is the output of <literal>RETURNING</literal>, <emphasis>not</emphasis> the underlying
239239
table that the statement modifies, that forms the temporary table that is
@@ -2184,7 +2184,8 @@ SELECT 2+2;
21842184

21852185
<para>
21862186
<productname>PostgreSQL</productname> allows <command>INSERT</command>,
2187-
<command>UPDATE</command>, and <command>DELETE</command> to be used as <literal>WITH</literal>
2187+
<command>UPDATE</command>, <command>DELETE</command>, and
2188+
<command>MERGE</command> to be used as <literal>WITH</literal>
21882189
queries. This is not found in the SQL standard.
21892190
</para>
21902191
</refsect2>

0 commit comments

Comments
 (0)