2016-04-09 1 views
1

私はこのようになり、PostgreSQLのテーブルの行の一連の持っている:PostgreSQLで可変数のキーを使用してJSON配列を集計するにはどうすればよいですか?

-[ 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" } 

私は学生、グループおよびサブグループでグループにそれらを好きで、各トラックのカウント状態になるだろうし。次のようなものがあります。

-[ 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} } 

問題のトラック数が異なる可能性があります。私は彼らの名前は知っているが、静的ではないので、単純な集約はできない。 PostgreSQL(9.5)でこれをどのように書くことができるでしょうか?操作に時間がかかるため、すべてのトラックを繰り返して集計する必要はありません。

答えて

1

json_each_textを使用して値を "取り消し"、json_object_aggを使用して再度結合することができます。

データ:

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" }'); 

問合せ:

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; 

出力:

enter image description here

関連する問題