188

Table 'animals':

animal_name animal_type
Tom         Cat
Jerry       Mouse
Kermit      Frog

Query:

SELECT 
array_to_string(array_agg(animal_name),';') animal_names,
array_to_string(array_agg(animal_type),';') animal_types
FROM animals;

Expected result:

Tom;Jerry;Kerimt, Cat;Mouse;Frog
OR
Tom;Kerimt;Jerry, Cat;Frog;Mouse

Can I be sure that order in first aggregate function will always be the same as in second. I mean I would't like to get:

Tom;Jerry;Kermit, Frog;Mouse,Cat
1
  • 8
    If you are on 9.0 you can replace the nested calls with a single string_agg() Commented Sep 6, 2011 at 9:15

4 Answers 4

511

Use an ORDER BY, like this example from the manual:

SELECT array_agg(a ORDER BY b DESC) FROM table;
Sign up to request clarification or add additional context in comments.

13 Comments

Note: ORDER BY in array_agg is introduced in PostgreSQL 9
Much better than the accepted answer assuming PostgreSQL 9+.
Could you please give sample with ORDER BY for select: SELECT array_agg(animal_name), array_agg(animal_type) FROM animals; ?
Note that this does not work for array_agg(DISTINCT a ORDER BY b)
When using for multiple columns you have to add parentheses: array_agg((a, b, c) ORDER BY b)
|
33

If you are on a PostgreSQL version < 9.0 then:

From: http://www.postgresql.org/docs/8.4/static/functions-aggregate.html

In the current implementation, the order of the input is in principle unspecified. Supplying the input values from a sorted subquery will usually work, however. For example:

SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;

So in your case you would write:

SELECT
array_to_string(array_agg(animal_name),';') animal_names,
array_to_string(array_agg(animal_type),';') animal_types
FROM (SELECT animal_name, animal_type FROM animals) AS x;

The input to the array_agg would then be unordered but it would be the same in both columns. And if you like you could add an ORDER BY clause to the subquery.

Comments

9

According to Tom Lane:

... If I read it right, the OP wants to be sure that the two aggregate functions will see the data in the *same* unspecified order. I think that's a pretty safe assumption. The server would have to go way out of its way to do differently, and it doesn't.

... So it is documented behavior that an aggregate without its own ORDER BY will see the rows in whatever order the FROM clause supplies them.

So I think it's fine to assume that all the aggregates, none of which uses ORDER BY, in your query will see input data in the same order. The order itself is unspecified though (which depends on the order the FROM clause supplies rows).

Source: PostgreSQL mailing list

2 Comments

This is the only answer whose author actually bothered to understand the question, namely whether the two aggregates would have the same order.
I note that, in the linked mail thread, Tom Lane explicitly recommends against adding an ORDER BY statement to each array_agg, for efficiency reasons.
3

Do this:

SELECT 
    array_to_string(array_agg(animal_name order by animal_name),';') animal_names,
    array_to_string(array_agg(animal_type order by animal_type),';') animal_types
FROM 
    animals;

2 Comments

...but this results in different orders depending on the input.
This is not what OP is asking, he wants to order both the agg results to be consistent (animal_name1 correspondig to animal_type1)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.