2015-12-08 7 views
10

Ich möchte zwei Spalten in einem "Array" bei der Gruppierung aggregieren.Postgres - Aggregate zwei Spalten in einem Element

Angenommen, eine Tabelle wie folgt:

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

ich aus dieser Tabelle und Gruppe von User_id auswählen möchte und friend_id erhalten und bestätigt als verkettete durch ein Komma getrennt Wert.

Zur Zeit habe ich dies:

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 

die mich bekommt:

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

Wie kann ich:

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

In gewissem Sinne Das hattest du, als du angefangen hast. :) –

+0

Aber was ich suche ist die Gruppierung unter einem Variablennamen. Dies ist nur ein Beispiel, es ist wirklich Teil einer größeren Join-Abfrage, die mehr Tabellen und Daten enthält. – SoluableNonagon

Antwort

12

Sie die Werte verketten können zusammen, bevor sie zur Einspeisung in die array_agg() Funktion:

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

Beachten Sie, dass dies Strings wie ''[2, t]' ', nicht verschachtelte Arrays erzeugt. Aktuelle Postgres-Arrays können keine Werte verschiedener Typen (wie Integer und Boolean) enthalten. –

+0

@DanielLyons Guter Punkt, ich bin nicht daran gewöhnt, verschachtelte Arrays wie diese in einem rdbms zu speichern, dachte also Strings. –

+0

Es ist in Ordnung; Es gibt keinen richtigen Weg, das Falsche zu tun. :) –

9

In Postgres 9.5 Sie Array von Arrays von Text erhalten:

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) 

oder ein Array von Arrays von 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

Nur Frage, welche Version verwenden Sie? 'array_agg' soll nicht' text [] 'oder' integer [] 'aggregieren ... – Eggplant

+0

Ops! PostgreSQL 9.5beta2 – klin

+0

Aha! Du hast mich da erwischt, ich habe mich gefragt, was für eine Art Hexerei das war :) 9.5 ist noch nicht veröffentlicht, also nehme ich an, dass das OP nach einer produktionsfertigen Lösung sucht. – 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

sehr einfache Lösung, danke. – SoluableNonagon

10

Sie könnten die Hässlichkeit der multidimentional Array und einige json verwenden, die gemischte Datentypen unterstützt:

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

Oder einige key : value Paare verwenden, da json ermöglicht, dass, so wird die Ausgabe mehr semantische sein wenn man so will:

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

Dies ist definitiv die richtige Antwort, Sie bekommen ein schönes Ergebnis als JSON (was wahrscheinlich ist, was wir alle sowieso wollen), und es sieht aus wie [[1990, "pm25"], [1995, "pm25"], [2000, "pm25"]] – chrismarx

Verwandte Themen