From 4781445223f33ca00713e3768d8e9d052596a09d Mon Sep 17 00:00:00 2001
From: "David G. Johnston" <David.G.Johnston@Gmail.com>
Date: Wed, 14 Dec 2022 02:28:49 +0000
Subject: [PATCH] Document aggregate order by influenced functions

---
 doc/src/sgml/func.sgml | 90 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 76 insertions(+), 14 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index ad31fdb737..9f6cfd6d42 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -19693,6 +19693,23 @@ SELECT NULLIF(value, '(none)') ...
    aggregation.
   </para>
 
+  <note>
+   <para>
+     The aggregates in this section all accept an optional
+     <literal>ORDER BY</literal> clause as described in the
+     general syntax rules for aggregates (see <xref linkend="syntax-aggregates" />).
+     On this page only those aggregates whose output will vary depending
+     upon the ordering of the inputs are shown with the clause.
+     It may be omitted, though the syntax here does not reflect this,
+     except in the case of float input aggregates.
+   </para>
+   <para>
+    <literal>input_sort_expr</literal> - An expression composed from the input
+    columns used to sort the input rows before providing them to the aggregate.
+    Typically one or more input column names separated by commas.
+   </para>
+  </note>
+
    <table id="functions-aggregate-table">
     <title>General-Purpose Aggregate Functions</title>
     <tgroup cols="2">
@@ -19716,24 +19733,43 @@ SELECT NULLIF(value, '(none)') ...
         <indexterm>
          <primary>array_agg</primary>
         </indexterm>
-        <function>array_agg</function> ( <type>anynonarray</type> )
+        <function>array_agg</function> ( <type>anynonarray</type> <literal>ORDER BY</literal> <literal>input_sort_expr</literal>)
         <returnvalue>anyarray</returnvalue>
        </para>
        <para>
         Collects all the input values, including nulls, into an array.
-       </para></entry>
+       </para>
+       <para>
+        <literal>WITH vals (v) AS ( VALUES (1),(3),(4),(3),(2) )</literal>
+       </para>
+       <para>
+        <literal>SELECT array_agg(v ORDER BY v) FROM vals</literal>
+        <returnvalue>{1,2,3,3,4}</returnvalue>
+       </para>
+       <para>
+        <literal>SELECT array_agg(DISTINCT v) FROM vals</literal>
+        <returnvalue>{1,2,3,4}</returnvalue>
+       </para>
+       </entry>
        <entry>No</entry>
       </row>
 
       <row>
        <entry role="func_table_entry"><para role="func_signature">
-        <function>array_agg</function> ( <type>anyarray</type> )
+        <function>array_agg</function> ( <type>anyarray</type> <literal>ORDER BY</literal> <literal>input_sort_expr</literal> )
         <returnvalue>anyarray</returnvalue>
        </para>
        <para>
         Concatenates all the input arrays into an array of one higher
         dimension.  (The inputs must all have the same dimensionality, and
         cannot be empty or null.)
+       </para>
+       <para>
+        <literal>WITH vals (v) AS ( VALUES (ARRAY[1,3]::integer[]), (ARRAY[3,2]), (ARRAY[1,4]) )</literal>
+       </para>
+       <para>
+        <literal>SELECT array_agg(v ORDER BY v) FROM vals</literal>
+        <returnvalue>{{1,3},{1,4},{3,2}}</returnvalue>
        </para></entry>
        <entry>No</entry>
       </row>
@@ -19762,11 +19798,11 @@ SELECT NULLIF(value, '(none)') ...
         <returnvalue>numeric</returnvalue>
        </para>
        <para role="func_signature">
-        <function>avg</function> ( <type>real</type> )
+        <function>avg</function> ( <type>real</type> <optional> <literal>ORDER BY</literal> <literal>input_sort_expr</literal> </optional> )
         <returnvalue>double precision</returnvalue>
        </para>
        <para role="func_signature">
-        <function>avg</function> ( <type>double precision</type> )
+        <function>avg</function> ( <type>double precision</type> <optional> <literal>ORDER BY</literal> <literal>input_sort_expr</literal> </optional> )
         <returnvalue>double precision</returnvalue>
        </para>
        <para role="func_signature">
@@ -19932,14 +19968,14 @@ SELECT NULLIF(value, '(none)') ...
         <indexterm>
          <primary>json_agg</primary>
         </indexterm>
-        <function>json_agg</function> ( <type>anyelement</type> )
+        <function>json_agg</function> ( <type>anyelement</type> <literal>ORDER BY</literal> <literal>input_sort_expr</literal> )
         <returnvalue>json</returnvalue>
        </para>
        <para role="func_signature">
         <indexterm>
          <primary>jsonb_agg</primary>
         </indexterm>
-        <function>jsonb_agg</function> ( <type>anyelement</type> )
+        <function>jsonb_agg</function> ( <type>anyelement</type> <literal>ORDER BY</literal> <literal>input_sort_expr</literal> )
         <returnvalue>jsonb</returnvalue>
        </para>
        <para>
@@ -19957,7 +19993,8 @@ SELECT NULLIF(value, '(none)') ...
         </indexterm>
         <function>json_object_agg</function> ( <parameter>key</parameter>
          <type>"any"</type>, <parameter>value</parameter>
-         <type>"any"</type> )
+         <type>"any"</type>
+         <literal>ORDER BY</literal> <literal>input_sort_expr</literal> )
         <returnvalue>json</returnvalue>
        </para>
        <para role="func_signature">
@@ -19966,7 +20003,8 @@ SELECT NULLIF(value, '(none)') ...
         </indexterm>
         <function>jsonb_object_agg</function> ( <parameter>key</parameter>
          <type>"any"</type>, <parameter>value</parameter>
-         <type>"any"</type> )
+         <type>"any"</type>
+         <literal>ORDER BY</literal> <literal>input_sort_expr</literal> )
         <returnvalue>jsonb</returnvalue>
        </para>
        <para>
@@ -19974,7 +20012,23 @@ SELECT NULLIF(value, '(none)') ...
         are coerced to text; value arguments are converted as
         per <function>to_json</function> or <function>to_jsonb</function>.
         Values can be null, but not keys.
-       </para></entry>
+       </para>
+       <para>
+        The keys of a jsonb document are definitionally unordered and unique,
+        the last value seen is kept.
+       </para>
+       <para>
+        <literal>WITH vals (k, v) AS ( VALUES ('key1','1'),('key0','2'),('key1','3' )</literal>
+       </para>
+       <para>
+        <literal>SELECT json_object_agg(k, v ORDER BY v) FROM vals</literal>
+        <returnvalue>{ "key1" : "1", "key0" : "2", "key1" : "3" }</returnvalue>
+       </para>
+       <para>
+        <literal>SELECT jsonb_object_agg(k, v ORDER BY v) FROM vals</literal>
+        <returnvalue>{"key0": "2", "key1": "3"}</returnvalue>
+       </para>
+       </entry>
        <entry>No</entry>
       </row>
 
@@ -20067,13 +20121,21 @@ SELECT NULLIF(value, '(none)') ...
        </para>
        <para role="func_signature">
         <function>string_agg</function> ( <parameter>value</parameter>
-         <type>bytea</type>, <parameter>delimiter</parameter> <type>bytea</type> )
+         <type>bytea</type>, <parameter>delimiter</parameter> <type>bytea</type>
+         <literal>ORDER BY</literal> <literal>input_sort_expr</literal> )
         <returnvalue>bytea</returnvalue>
        </para>
        <para>
         Concatenates the non-null input values into a string.  Each value
         after the first is preceded by the
         corresponding <parameter>delimiter</parameter> (if it's not null).
+       </para>
+       <para>
+        <literal>WITH vals (v) AS ( VALUES ('Larry', 'Curley', 'Moe'::text) )</literal>
+       </para>
+       <para>
+        <literal>SELECT array_agg(v, ', ' ORDER BY v) FROM vals</literal>
+        <returnvalue>Curley, Larry, Moe</returnvalue>
        </para></entry>
        <entry>No</entry>
       </row>
@@ -20099,11 +20161,11 @@ SELECT NULLIF(value, '(none)') ...
         <returnvalue>numeric</returnvalue>
        </para>
        <para role="func_signature">
-        <function>sum</function> ( <type>real</type> )
+        <function>sum</function> ( <type>real</type> <optional> <literal>ORDER BY</literal> <literal>input_sort_expr</literal> </optional> )
         <returnvalue>real</returnvalue>
        </para>
        <para role="func_signature">
-        <function>sum</function> ( <type>double precision</type> )
+        <function>sum</function> ( <type>double precision</type> <optional> <literal>ORDER BY</literal> <literal>input_sort_expr</literal> </optional> )
         <returnvalue>double precision</returnvalue>
        </para>
        <para role="func_signature">
@@ -20125,7 +20187,7 @@ SELECT NULLIF(value, '(none)') ...
         <indexterm>
          <primary>xmlagg</primary>
         </indexterm>
-        <function>xmlagg</function> ( <type>xml</type> )
+        <function>xmlagg</function> ( <type>xml</type> <literal>ORDER BY</literal> <literal>input_sort_expr</literal> )
         <returnvalue>xml</returnvalue>
        </para>
        <para>
-- 
2.25.1

