WL#11574: Add JSON_ARRAYAGG and JSON_OBJECTAGG windowing functions

Affects: Server-8.0   —   Status: Complete

Add windowing support for JSON_ARRAYAGG and JSON_OBJECTAGG aggregate functions.

This is a followup of the work done in WL#9236. Add SQL window functions.
Please refer to that WL for a general background and specifications.

See also WL#9727, WL#9603 and WL#11573.

JSON_ARRAYAGG and JSON_OBJECTAGG have the same semantics as that of their
grouped aggregate counterparts except that all the rules of window specification
are added to it. A JSON_ARRAY or JSON_OBJECT is returned for every row within a
frame based on the window frame specification.
For example:
create table t1 ( id integer, attribute char(50), value char(50));
insert into t1 values (1, 'color', 'red'),
                      (1, 'shape', 'square'),
                      (1, 'fabric', 'silk'),
                      (1, 'fabric', 'cotton'),
                      (1, 'shape', 'rectangle'),
                      (1, 'color', 'green'),
                      (2, 'color', 'green'),
                      (2, 'shape', 'triangle'),
                      (2, 'shape', 'circle'),
                      (2, 'color', 'yellow'),
                      (2, 'fabric', 'cotton');
JSON_ARRAYAGG

Single Partition:

mysql> SELECT  id, attribute, JSON_ARRAYAGG(attribute) OVER w attribute_arr FROM
t1 WINDOW w AS (ORDER BY id);
+------+-----------+--------------------------------------------------------------------------------------------------------+
| id   | attribute | attribute_arr                                             
                                            |
+------+-----------+--------------------------------------------------------------------------------------------------------+
|    1 | color     | ["color", "shape", "fabric", "fabric", "shape", "color"]  
                                            |
|    1 | shape     | ["color", "shape", "fabric", "fabric", "shape", "color"]  
                                            |
|    1 | fabric    | ["color", "shape", "fabric", "fabric", "shape", "color"]  
                                            |
|    1 | fabric    | ["color", "shape", "fabric", "fabric", "shape", "color"]  
                                            |
|    1 | shape     | ["color", "shape", "fabric", "fabric", "shape", "color"]  
                                            |
|    1 | color     | ["color", "shape", "fabric", "fabric", "shape", "color"]  
                                            |
|    2 | color     | ["color", "shape", "fabric", "fabric", "shape", "color",
"color", "shape", "shape", "color", "fabric"] |
|    2 | shape     | ["color", "shape", "fabric", "fabric", "shape", "color",
"color", "shape", "shape", "color", "fabric"] |
|    2 | shape     | ["color", "shape", "fabric", "fabric", "shape", "color",
"color", "shape", "shape", "color", "fabric"] |
|    2 | color     | ["color", "shape", "fabric", "fabric", "shape", "color",
"color", "shape", "shape", "color", "fabric"] |
|    2 | fabric    | ["color", "shape", "fabric", "fabric", "shape", "color",
"color", "shape", "shape", "color", "fabric"] |
+------+-----------+--------------------------------------------------------------------------------------------------------+
11 rows in set (0.00 sec)


With window frames:

SELECT  id, attribute, JSON_ARRAYAGG(attribute) OVER w attribute_arr
  FROM t1 WINDOW w AS (PARTITION BY id ORDER BY attribute
                       ROWS BETWEEN 2 PRECEDING  AND 1 FOLLOWING);
+------+-----------+----------------------------------------+
| id   | attribute | attribute_arr                          |
+------+-----------+----------------------------------------+
|    1 | color     | ["color", "color"]                     |
|    1 | color     | ["color", "color", "fabric"]           |
|    1 | fabric    | ["color", "color", "fabric", "fabric"] |
|    1 | fabric    | ["color", "fabric", "fabric", "shape"] |
|    1 | shape     | ["fabric", "fabric", "shape", "shape"] |
|    1 | shape     | ["fabric", "shape", "shape"]           |
|    2 | color     | ["color", "color"]                     |
|    2 | color     | ["color", "color", "fabric"]           |
|    2 | fabric    | ["color", "color", "fabric", "shape"]  |
|    2 | shape     | ["color", "fabric", "shape", "shape"]  |
|    2 | shape     | ["fabric", "shape", "shape"]           |
+------+-----------+----------------------------------------+
11 rows in set (0.00 sec)

JSON_OBJECT AGG -

Single partition:

SELECT  id, JSON_OBJECTAGG(attribute,value) OVER w attribute_object
  FROM t1 WINDOW w AS (PARTITION BY id);
+------+--------------------------------------------------------------+
| id   | attribute_object                                             |
+------+--------------------------------------------------------------+
|    1 | {"color": "green", "shape": "rectangle", "fabric": "cotton"} |
|    1 | {"color": "green", "shape": "rectangle", "fabric": "cotton"} |
|    1 | {"color": "green", "shape": "rectangle", "fabric": "cotton"} |
|    1 | {"color": "green", "shape": "rectangle", "fabric": "cotton"} |
|    1 | {"color": "green", "shape": "rectangle", "fabric": "cotton"} |
|    1 | {"color": "green", "shape": "rectangle", "fabric": "cotton"} |
|    2 | {"color": "yellow", "shape": "circle", "fabric": "cotton"}   |
|    2 | {"color": "yellow", "shape": "circle", "fabric": "cotton"}   |
|    2 | {"color": "yellow", "shape": "circle", "fabric": "cotton"}   |
|    2 | {"color": "yellow", "shape": "circle", "fabric": "cotton"}   |
|    2 | {"color": "yellow", "shape": "circle", "fabric": "cotton"}   |
+------+--------------------------------------------------------------+
11 rows in set (0.00 sec)

With frames:

Example 1:

SELECT  id, attribute, JSON_OBJECTAGG(attribute,id) OVER w attribute_object
  FROM t1 WINDOW w AS (PARTITION BY id ORDER BY attribute
                       ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING);
+------+-----------+---------------------------------------+
| id   | attribute | attribute_object                      |
+------+-----------+---------------------------------------+
|    1 | color     | {"color": 1}                          |
|    1 | color     | {"color": 1, "fabric": 1}             |
|    1 | fabric    | {"color": 1, "fabric": 1}             |
|    1 | fabric    | {"color": 1, "shape": 1, "fabric": 1} |
|    1 | shape     | {"shape": 1, "fabric": 1}             |
|    1 | shape     | {"shape": 1, "fabric": 1}             |
|    2 | color     | {"color": 2}                          |
|    2 | color     | {"color": 2, "fabric": 2}             |
|    2 | fabric    | {"color": 2, "shape": 2, "fabric": 2} |
|    2 | shape     | {"color": 2, "shape": 2, "fabric": 2} |
|    2 | shape     | {"shape": 2, "fabric": 2}             |
+------+-----------+---------------------------------------+
11 rows in set (0.01 sec)

Example 2:

SELECT  id, attribute, JSON_OBJECTAGG(id,attribute) OVER w attribute_object
  FROM t1 WINDOW w AS (PARTITION BY id ORDER BY attribute
                       ROWS BETWEEN 2 PRECEDING and 1 FOLLOWING);
+------+-----------+------------------+
| id   | attribute | attribute_object |
+------+-----------+------------------+
|    1 | color     | {"1": "color"}   |
|    1 | color     | {"1": "fabric"}  |
|    1 | fabric    | {"1": "fabric"}  |
|    1 | fabric    | {"1": "shape"}   |
|    1 | shape     | {"1": "shape"}   |
|    1 | shape     | {"1": "shape"}   |
|    2 | color     | {"2": "color"}   |
|    2 | color     | {"2": "fabric"}  |
|    2 | fabric    | {"2": "shape"}   |
|    2 | shape     | {"2": "shape"}   |
|    2 | shape     | {"2": "shape"}   |
+------+-----------+------------------+
11 rows in set (0.00 sec)

Note that in the example 2 above, since the key value is same as the
partitioning key, only the last value within the frame is retained. This is in
line with the grouped aggregate specification where only the last value for any
key (if there are duplicate keys) is retained in the result.
For details about semantics of JSON aggregate functions, please refer to WL#7987. 
Also check -
https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_json-arrayagg
https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_json-objectagg