SELECT id, array_agg((e.*))
FROM containers
JOIN elements AS e(eid,id)
USING(id)
GROUP BY id;
id |
array_agg |
1 |
{"(1,1)","(2,1)"} |
2 |
{"(3,2)"} |
demo at db<>fiddle
Your array_agg(*)
concept isn't incorrect but that's not the right, or complete syntax for it.
An asterisk *
as an aggregate function argument doesn't mean the same thing as it does in a select
list: I take that you expected it to be interpreted as all columns, the way it works when used directly in the select list. Meanwhile, as an aggregate function argument, it means the opposite: no columns.
arg_data_type
An input data type on which this aggregate function operates. To create a zero-argument aggregate function, write *
in place of the list of argument specifications. (An example of such an aggregate is count(*)
.)
It's also mentioned in the doc that you linked:
The fourth form invokes the aggregate once for each input row; since no particular input value is specified, it is generally only useful for the count(*)
aggregate function.
There's no zero-argument version of the array_agg()
function defined in a standard PostgreSQL build, so an array_agg(*)
won't work. Note how the error message you got says the function it couldn't find is a function with no arguments (empty parentheses instead of an asterisk or a list of types corresponding to all fields):
ERROR: function array_agg() does not exist
LINE 4: SELECT elements.id, array_agg(*)
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
There is only a single-element version, and you can by all means pass whole rows into it, as long as you parenthesise and qualify the *
expression, like in the example up top.
Aliasing the elements
fields to match join column names enables JOIN..USING
and stops it from listing them twice.
There's a slight advantage of array_agg((e.*))
over already mentioned array_agg(e)
: the former lets you mix things in. If you don't add anything, it works exactly the same:
SELECT id
, array_agg(e)
, array_agg((e))
, array_agg((e.*))
FROM containers
JOIN elements AS e(eid,id)
USING(id)
GROUP BY id;
id |
array_agg |
array_agg |
array_agg |
1 |
{"(1,1)","(2,1)"} |
{"(1,1)","(2,1)"} |
{"(1,1)","(2,1)"} |
2 |
{"(3,2)"} |
{"(3,2)"} |
{"(3,2)"} |
If you do add something, the tablename-as-select-expression syntax will nest the record:
SELECT id
, array_agg((e.* , 'x' , id*e.eid))
, array_agg((e , 'x' , id*e.eid))
FROM containers
JOIN elements AS e(eid,id)
USING(id)
GROUP BY id;
id |
array_agg |
array_agg |
1 |
{"(1,1,x,1)","(2,1,x,2)"} |
{"("(1,1)",x,1)","("(2,1)",x,2)"} |
2 |
{"(3,2,x,6)"} |
{"("(3,2)",x,6)"} |
Keep in mind that if you do mix something in, the resulting type will no longer be a regular array type elements[]
but a pseudo-type record[]
and those cannot be used in column definitions (e.g. create table..as..
and create view..as..
will refuse to accept a query with a pseudo-type column).
[1, 1]
[2, 1]
etc? What if the columns ofelements
were different types, such as strings or dates?