Postgres - aggregate two columns into one item

SqlArraysPostgresqlAggregate Functions

Sql Problem Overview


I would like to aggregate two columns into one "array" when grouping.

Assume a table like so:

friends_map:
=================================
user_id    friend_id    confirmed
=================================
1          2            true
1          3            false
2          1            true
2          3            true
1          4            false

I would like to select from this table and group by user_id and get friend_id and confirmed as a concatenated value separated by a comma.

Currently I have this:

SELECT user_id, array_agg(friend_id) as friends, array_agg(confirmed) as confirmed
FROM friend_map
WHERE user_id = 1
GROUP BY user_id

which gets me:

=================================
user_id    friends      confirmed
=================================
1         [2,3,4]       [t, f, f]

How can I get:

=================================
user_id    friends     
=================================
1         [ [2,t], [3,f], [4,f] ]

Sql Solutions


Solution 1 - Sql

SELECT user_id, array_agg((friend_id, confirmed)) as friends
FROM friend_map
WHERE user_id = 1
GROUP BY user_id

user_id |           array_agg            
--------+--------------------------------
      1 | {"(2,true)","(3,false)","(4,false)"}

Solution 2 - Sql

You could avoid the ugliness of the multidimentional array and use some json which supports mixed datatypes:

SELECT user_id, json_agg(json_build_array(friend_id, confirmed)) AS friends 
	FROM friends_map 
	WHERE user_id = 1
	GROUP BY user_id

Or use some key : value pairs since json allows that, so your output will be more semantic if you like:

SELECT user_id, json_agg(json_build_object(
		'friend_id', friend_id, 
		'confirmed', confirmed
	)) AS friends 
	FROM friends_map 
	WHERE user_id = 1
	GROUP BY user_id;

Solution 3 - Sql

You can concatenate the values together prior to feeding them into the array_agg() function:

SELECT user_id, array_agg('[' || friend_id || ',' || confirmed || ']') as friends
FROM friends_map
WHERE user_id = 1
GROUP BY user_id

Demo: SQL Fiddle

Solution 4 - Sql

In Postgres 9.5 you can obtain array of arrays of text:

SELECT user_id, array_agg(array[friend_id::text, confirmed::text])
FROM friend_map
WHERE user_id = 1
GROUP BY user_id;

 user_id |           array_agg            
---------+--------------------------------
       1 | {{2,true},{3,false},{4,false}}
(1 row)

or array of arrays of int:

SELECT user_id, array_agg(array[friend_id, confirmed::int])
FROM friend_map
WHERE user_id = 1
GROUP BY user_id;

 user_id |      array_agg      
---------+---------------------
       1 | {{2,1},{3,0},{4,0}}
(1 row)	

Solution 5 - Sql

You can use: array[]

Just do that:

SELECT user_id, array[friend_id, confirmed]
FROM friend_map
WHERE user_id = 1
GROUP BY 1;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSoluableNonagonView Question on Stackoverflow
Solution 1 - SqlIvan BurlutskiyView Answer on Stackoverflow
Solution 2 - SqlEggplantView Answer on Stackoverflow
Solution 3 - SqlHart COView Answer on Stackoverflow
Solution 4 - SqlklinView Answer on Stackoverflow
Solution 5 - Sqlroi3363View Answer on Stackoverflow