2

次の表があります。

CREATE TABLE mytable (
  id       serial PRIMARY KEY
, employee text UNIQUE NOT NULL
, data     jsonb
);

次のデータを使用します。

INSERT INTO mytable (employee, data)
VALUES
 ('Jim', '{"sales_tv": [{"value": 10, "yr": "2010", "loc": "us"}, {"value": 5, "yr": "2011", "loc": "europe"}, {"value": 40, "yr": "2012", "loc": "asia"}], "sales_radio": [{"value": 11, "yr": "2010", "loc": "us"}, {"value": 8, "yr": "2011", "loc": "china"}, {"value": 76, "yr": "2012", "loc": "us"}], "another_key": "another value"}'),
 ('Rob', '{"sales_radio": [{"value": 7, "yr": "2014", "loc": "japan"}, {"value": 3, "yr": "2009", "loc": "us"}, {"value": 37, "yr": "2011", "loc": "us"}], "sales_tv": [{"value": 4, "yr": "2010", "loc": "us"}, {"value": 18, "yr": "2011", "loc": "europe"}, {"value": 28, "yr": "2012", "loc": "asia"}], "another_key": "another value"}')

「sales_tv」と「sales_radio」以外にもキーがあることに注意してください。以下のクエリでは、「sales_tv」と「sales_radio」に注目する必要があります。

Jim の 2012 年のすべての売上を検索する必要があります。「sales_」で始まり、それをオブジェクトに入れます (必要なのは、製品が販売されたものと値だけです)。例えば:

    employee   | sales_
    Jim        | {"sales_tv": 40, "sales_radio": 76}

私が持っている:

SELECT * FROM mytable,
  (SELECT l.key, l.value FROM mytable, lateral jsonb_each_text(data) AS l
    WHERE key LIKE 'sales_%') AS a,
  jsonb_to_recordset(a.value::jsonb) AS d(yr text, value float)
  WHERE mytable.employee = 'Jim'
  AND d.yr = '2012'

しかし、ジムのデータだけを取得することさえできないようです. 代わりに私は得る:

employee | key         |  value
-------- |------       | -----
Jim      | sales_tv    |  [{"yr": "2010", "loc": "us", "value": 4}, {"yr": "2011", "loc": "europe", "value": 18}, {"yr": "2012", "loc": "asia", "value": 28}]
Jim      | sales_tv    |  [{"yr": "2010", "loc": "us", "value": 10}, {"yr": "2011", "loc": "europe", "value": 5}, {"yr": "2012", "loc": "asia", "value": 40}]
Jim      | sales_radio |  [{"yr": "2010", "loc": "us", "value": 11}, {"yr": "2011", "loc": "china", "value": 8}, {"yr": "2012", "loc": "us", "value": 76}]
4

2 に答える 2

4

最初の結合の結果をテキスト文字列ではなく JSON として扱うため、jsonb_each()代わりにjsonb_each_text()次を使用します。

SELECT t.employee, json_object_agg(a.k, d.value) AS sales
FROM   mytable t
JOIN   LATERAL jsonb_each(t.data) a(k,v) ON a.k LIKE 'sales_%'
JOIN   LATERAL jsonb_to_recordset(a.v) d(yr text, value float) ON d.yr = '2012'
WHERE  t.employee = 'Jim'  -- works because employee is unique
GROUP  BY 1;

GROUP BY 1の省略形ですGROUP BY t.employee
結果:

employee | sales
---------+--------
Jim      | '{ "sales_tv" : 40, "sales_radio" : 76 }'

また、クエリを解きほぐして単純化しました。

json_object_agg()名前と値のペアを JSON オブジェクトとして集約するのに役立ちます。必要に応じてオプションでキャストするjsonbjsonb_object_agg()、Postgres 9.5 以降で使用します。

明示的なJOIN構文を使用して、最も明白な場所に条件を追加します。明示的な構文なしで
同じ:JOIN

SELECT t.employee, json_object_agg(a.k, d.value) AS sales
FROM   mytable t
     , jsonb_each(t.data)      a(k,v) 
     , jsonb_to_recordset(a.v) d(yr text, value float)
WHERE  t.employee = 'Jim'
AND    a.k LIKE 'sales_%'
AND    d.yr = '2012'
GROUP  BY 1;
于 2015-07-22T00:52:44.533 に答える
0

最初のクエリは次のように解決できます (ヒップからの撮影、ここでは PG 9.4 へのアクセスはありません)。

SELECT employee, json_object_agg(key, sales)::jsonb AS sales_
FROM (
  SELECT t.employee, j.key, sum((e->>'value')::int) AS sales
  FROM mytable t,
       jsonb_each(t.data) j,
       jsonb_array_elements(j.value) e
  WHERE t.employee = 'Jim'
    AND j.key like 'sales_%'
    AND e->>'yr' = '2012'
  GROUP BY t.employee, j.key) sub
GROUP BY employee;

ここでの秘訣は、LATERAL結合を使用してオブジェクトの外側のレイヤーを「剥がし」、jsonbより深いデータを取得することです。このクエリは、ジムが複数の場所で販売を行っている可能性があることを前提としています。

(クエリ2に取り組んでいます)

于 2015-07-22T01:09:35.777 に答える