3

次のテーブル構造があります。

CREATE TABLE mytable (
  id   serial PRIMARY KEY,
  data jsonb
);

そして、次のデータ (簡潔にするために部分的なものです...年のランダム性と売上/支出の年が互いに一致していないことに注意してください):

INSERT INTO mytable (data)
VALUES
('{"employee": "Jim Romo", 
 "sales": [{"value": 10, "yr": "2012"}, {"value": 5, "yr": "2013"}, {"value": 40, "yr": "2014"}],
 "expenses": [{"value": 2, "yr": "2007"}, {"value": 1, "yr": "2013"}, {"value": 3, "yr": "2014"}], 
 "product": "tv", "customer": "1", "updated": "20150501"
}'),
('{"employee": "Jim Romo", 
 "sales": [{"value": 10, "yr": "2012"}, {"value": 5, "yr": "2013"}, {"value": 41, "yr": "2014"}],
 "expenses": [{"value": 2, "yr": "2009"}, {"value": 3, "yr": "2013"}, {"value": 3, "yr": "2014"}], 
 "product": "tv", "customer": "2", "updated": "20150312"
}'),
('{"employee": "Jim Romo", 
 "sales": [{"value": 20, "yr": "2012"}, {"value": 25, "yr": "2013"}, {"value": 33, "yr": "2014"}],
 "expenses": [{"value": 8, "yr": "2012"}, {"value": 12, "yr": "2014"}, {"value": 5, "yr": "2009"}], 
 "product": "radio", "customer": "2", "updated": "20150311"
}'),
('{"employee": "Bill Baker", 
 "sales": [{"value": 1, "yr": "2010"}, {"value": 2, "yr": "2009"}, {"value": 3, "yr": "2014"}],
 "expenses": [{"value": 3, "yr": "2011"}, {"value": 1, "yr": "2012"}, {"value": 7, "yr": "2013"}], 
 "product": "tv", "customer": "1", "updated": "20150205"
}'),
('{"employee": "Bill Baker", 
 "sales": [{"value": 10, "yr": "2010"}, {"value": 12, "yr": "2011"}, {"value": 3, "yr": "2014"}],
 "expenses": [{"value": 4, "yr": "2011"}, {"value": 7, "yr": "2009"}, {"value": 4, "yr": "2013"}], 
 "product": "radio", "customer": "1", "updated": "20150204"
}'),
('{"employee": "Jim Romo",
 "sales": [{"value": 22, "yr": "2009"}, {"value": 17, "yr": "2013"}, {"value": 35, "yr": "2014"}],
 "expenses": [{"value": 14, "yr": "2011"}, {"value": 13, "yr": "2014"}, {"value": 8, "yr": "2013"}], 
 "product": "tv", "customer": "3", "updated": "20150118"
}')

従業員ごとに、最新の更新行を評価し、2014 年のテレビ売上が 30 を超える従業員を見つける必要があります。そこから、テレビの平均支出が 5 未満の従業員をさらにフィルター処理する必要があります。平均については、最新の行だけでなく、テレビのすべての費用。

私の期待される出力は1行になります:

employee    | customer | 2014 tv sales   |  2013 avg tv expenses
------------+----------+-----------------+----------------------
Jim Romo    |    1     |   40            |  4

私は(ちょっと)どちらか一方を行うことができますが、両方はできません:

を。2014 年の売り上げが 30 を超える (ただし、最新の「テレビ」の売り上げは取得できません ;(

SELECT * FROM mytable WHERE (SELECT (a->>'value')::float FROM
    (SELECT jsonb_array_elements(data->'sales') as a) as b 
    WHERE a @> json_object(ARRAY['yr', '2014'])::jsonb) > 30

b. 2013 年の平均支出を取得します (これは平均テレビ支出である必要があります)

SELECT avg((a->>'value')::numeric) FROM  
  (SELECT jsonb_array_elements(data->'expenses') as a FROM mytable) as b
  WHERE a @> json_object(ARRAY['yr', '2013'])::jsonb

編集: これは非常に大きなテーブルになる可能性があるため、postgresql と jsonb の両方に慣れていないため、パフォーマンスとインデックス作成のニーズに関するコメントをいただければ幸いです。

編集#2:両方の答えを試しましたが、どちらも大きなテーブルでは効率的ではないようです;(

4

1 に答える 1