2015-12-08 14 views
10

Vorrei aggregare due colonne in un "array" durante il raggruppamento.Postgres - aggregare due colonne in un elemento

assumere una tabella in questo modo:

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

desidero selezionare da questa tabella e gruppo da user_id e ricevere friend_id e confermato come valore concatenato separati da una virgola.

Attualmente ho questo:

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 

che mi fa:

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

Come posso ottenere:

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

In un certo senso , è quello che hai avuto quando hai iniziato. :) –

+0

Ma quello che sto cercando è il raggruppamento sotto un nome di variabile. Questo è solo un esempio, fa davvero parte di una query di join più ampia, che contiene più tabelle e dati. – SoluableNonagon

risposta

12

è possibile concatenare i valori insieme prima di nutrirli in la funzione array_agg():

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

Demo: SQL Fiddle

+1

Nota che stiamo costruendo stringhe come ''[2, t]'', non array annidati. Gli array Postgres effettivi non possono contenere valori di tipi diversi (come intero e booleano). –

+0

@DanielLyons Buon punto, non sono abituato a pensare di archiviare array annidati come questo in un rdbms, quindi pensavo alle stringhe. –

+0

Va bene; non c'è un modo giusto di fare la cosa sbagliata. :) –

9

In Postgres 9.5 è possibile ottenere array di array di testo:

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) 

o array di array di 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) 
+0

Solo domanda, quale versione stai usando? 'array_agg' non dovrebbe aggregare' text [] 'o' intero [] '... – Eggplant

+0

Ops! PostgreSQL 9.5beta2 – klin

+0

Aha! Mi hai portato lì, mi chiedevo che tipo di * stregoneria * fosse così :) 9.5 non è ancora stato rilasciato, quindi presumo che l'OP stia cercando una soluzione pronta per la produzione. – Eggplant

18
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)"} 
+1

soluzione molto semplice, grazie. – SoluableNonagon

10

Si potrebbe evitare la bruttezza del matrice multidimensionale e utilizzare alcuni JSON che supporta tipi di dati misti:

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

o usare qualche key : value coppie in quanto JSON consente che, così l'output sarà più semantica se ti piace:

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; 
+0

Questa è sicuramente la risposta giusta, si ottiene un buon risultato come json (che è probabilmente quello che tutti noi vogliamo comunque), e sembra [[1990, "pm25"], [1995, "pm25"], [2000, "PM25"]] – chrismarx

Problemi correlati