2

I'm storing AdWords report data in Postgres. Each report is stored in a table named Reports, which has a jsonb column named 'data'. Each report has json stored in its 'data' field that looks that looks like this:

[
  {
    match_type: "exact",
    search_query: "gm hubcaps",
    conversions: 2,
    cost: 1.24
  },
  {
    match_type: "broad",
    search_query: "gm auto parts",
    conversions: 34,
    cost: 21.33
  },
  {
    match_type: "phrase",
    search_query: "silverdo headlights",
    conversions: 63,
    cost: 244.05
  }
]

What I want to do is query off these data hashes and sum up the total number of conversions for a given report. I've looked though the Postgresql docs and it looks like you can only really do calculations on hashes, not arrays of hashes like this. Is what I'm trying to do possible in postgres? Do I need to make a temp table out of this array and do calculations off that? Or can I use a stored procedure?

I'm using Postgresql 9.4

EDIT The reason I'm not just using a regular, normalized table is that this is just one example of how report data could be structured. In my project, reports have to allow arbitrary keys, because they are populated by users uploading CSV's with any columns they like. It's basically just a way to get around having arbitrarily many, user-created tables.

4

2 に答える 2

1

私がやりたいことは、これらのデータ ハッシュをクエリして、変換を合計することです

最速の方法はjsonb_populate_recordset(). ただし、登録された行タイプが必要です。

CREATE TEMP TABLE report_data (
--   match_type text    -- commented out, because we only need ..
-- , search_query text  -- .. conversions for this query
     conversions int
-- , cost numeric
);

一時テーブルは、行タイプをアドホックに登録する 1 つの方法です。この関連する回答の詳細な説明:

情報が不足しているため、PK として テーブルreportを想定します。report_id

SELECT r.report_id, sum(d.conversions) AS sum_conversions
FROM   report r
LEFT   JOIN LATERAL jsonb_populate_recordset(null::report_data, r.data) d ON true
-- WHERE  r.report_id = 12345  -- only for given report?
GROUP  BY 1;

NULL または空、または JSON 配列が空であっても、LEFT JOIN確実に結果が得られます。data

基になるテーブルの単一行からの合計の場合、これはより高速です。

SELECT d.sum_conversions
FROM   report r
LEFT   JOIN LATERAL (
   SELECT sum(conversions) AS sum_conversions
   FROM   jsonb_populate_recordset(null::report_data, r.data)
   ) d ON true
WHERE  r.report_id = 12345;  -- enter report_id here

代替jsonb_array_elements()(登録された行タイプは必要ありません):

SELECT d.sum_conversions
FROM   report r
LEFT   JOIN LATERAL (
   SELECT sum((value->>'conversions')::int) AS sum_conversions
   FROM   jsonb_array_elements(r.data)
   ) d ON true
WHERE  r.report_id = 12345;  -- enter report_id here

通常、これは単純な正規化されたテーブルとして実装します。ここでは JSON の利点はわかりません (ただし、追加したように、アプリケーションで JSON が必要なようです)。

于 2015-03-19T15:19:33.137 に答える
1

使用できますunnest

select sum(conv) from
(select d->'conversion' as conv from
(select unnest(data) as d from <your table>) all_data
) all_conv

免責事項: 私は Pg 9.2 を持っていないので、自分でテストできませんでした。

編集:これは、あなたが言及した配列がPostgresql配列である、つまり、data列のデータ型がcharacter varying[]. が json 配列であることを意味する場合は、代わりにdataを使用できるはずです。json_array_elementsunnest

于 2015-03-19T14:36:33.913 に答える