2016-04-09 2 views
1

Ich habe eine Reihe von Zeilen in einer PostgreSQL-Tabelle, die wie folgt aussehen:Wie kann ich ein JSON-Array mit einer variablen Anzahl von Schlüsseln in PostgreSQL zusammenfassen?

-[ RECORD 1 ]--------------------------------------------------------------------- 
student  | e04c0ae4709340cb8e03c52f444e723f 
group  | 1 
subgroup | 1 
variable | VAR1 
status  | { "track_A" : "Done", "track_B" : "Done", "track_C" : "To Do" } 
-[ RECORD 2 ]--------------------------------------------------------------------- 
student  | e04c0ae4709340cb8e03c52f444e723f 
group  | 1 
subgroup | 1 
variable | VAR2 
status  | { "track_A" : "To Do", "track_B" : "Done", "track_C" : "To Do" } 
-[ RECORD 3 ]--------------------------------------------------------------------- 
student  | 849d1e6a0c2b4530a2b550829df94556 
group  | 0 
subgroup | 1 
variable | VAR3 
status  | { "track_A" : "Done", "track_B" : "To Do", "track_C" : "To Do" } 

Ich möchte sie zu einer Gruppe von Studenten, Gruppen und Untergruppen und einen Zählerstand für jede Strecke. Etwas wie:

-[ RECORD 1 ]--------------------------------------------------------------------- 
student  | e04c0ae4709340cb8e03c52f444e723f 
group  | 1 
subgroup | 1 
totals  | { "track_A" : {"done": 1, "to_do": 1}, {"track_B" : {"done": 0, "to_do": 2}, "track_C" : {"done": 0, "to_do": 2} } 

Das Problem ist, dass die Anzahl der Tracks variieren kann. Ich kenne ihre Namen, aber sie sind nicht statisch, also kann ich keine einfache Aggregation machen. Irgendwelche Vorschläge, wie ich das in PostgreSQL (9.5) schreiben könnte? Ich möchte nicht über alle Spuren iterieren und aggregieren, da die Operation einige Zeit in Anspruch nehmen wird.

Antwort

1

Sie könnten json_each_text zu "unest" Werten und json_object_agg verwenden, um es wieder zu kombinieren.

Daten:

DROP TABLE IF EXISTS tab; 
CREATE TABLE tab(student VARCHAR(36), "group" INT, subgroup INT, 
       variable VARCHAR(20), status JSON);   

INSERT INTO tab(student, "group", subgroup, variable, status) 
VALUES 
('e04c0ae4709340cb8e03c52f444e723f',1,1,'VAR1' 
,'{ "track_A" : "Done", "track_B" : "Done", "track_C" : "To Do" }'), 
('e04c0ae4709340cb8e03c52f444e723f',1,1,'VAR2' 
, '{ "track_A" : "To Do", "track_B" : "Done", "track_C" : "To Do" }') 
,('849d1e6a0c2b4530a2b550829df94556',0,1,'VAR3' 
,'{ "track_A" : "Done", "track_B" : "To Do", "track_C" : "To Do" }'); 

Abfrage:

WITH cte AS 
(
    SELECT student, "group", subgroup, k 
    ,COUNT(CASE WHEN v='Done' THEN 1 END) AS Done 
    ,COUNT(CASE WHEN v='To Do' THEN 1 END) AS To_do 
    FROM tab 
    ,LATERAL json_each_text(status) s(k,v) 
    GROUP BY student, "group", subgroup, k 
), cte2 AS 
(
    SELECT student, "group", subgroup, k, json_object_agg(s.status, s.cnt) AS j 
    FROM cte 
    ,LATERAL (VALUES('Done', Done),('To Do', To_Do)) AS s(status, cnt) 
    GROUP BY student, "group", subgroup, k 
) 
SELECT student, "group", subgroup 
     ,json_object_agg(k, j) AS totals 
FROM cte2 
GROUP BY student, "group", subgroup; 

Ausgang:

enter image description here

Verwandte Themen