2015-03-19 63 views
2

我在AdWords中存儲AdWords報告數據。每個報告存儲在一個名爲Reports的表中,其中有一個名爲'data'的jsonb列。每個報告都有存儲在它的「數據」字段的JSON看起來,看起來像這樣:如何計算Postgres中的json數據

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

我想要做的就是查詢關閉這些數據散列和總結轉換的總數爲給定的報告。我查看了Postgresql文檔,看起來你只能真正對散列進行計算,而不是像這樣的散列數組。我正在嘗試在postgres中做什麼?我是否需要從這個數組中創建一個臨時表並進行計算?或者我可以使用存儲過程嗎?

我使用PostgreSQL 9.4

編輯 我不只是使用普通的,標準化的表的原因是,這僅僅是一個的報告數據是如何被結構化的例子。在我的項目中,報告必須允許使用任意鍵,因爲用戶使用任何他們喜歡的列上傳CSV。這基本上只是一種繞過任意多個用戶創建表的方式。

+1

也許你應該把它作爲一個永久表,因爲這個結構完全符合關係模型並保持在JSON中意味着每個查詢都將變得更加複雜和低效。 – 2015-03-19 15:05:50

+0

表格定義(psql中的'\ d tbl')和你的Postgres版本對於這個問題是必不可少的*。另外:總和慣例*每個報告*或總體? – 2015-03-19 15:10:13

回答

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 
); 

臨時表是一種註冊行類型ad-hoc的方法。在這個相關答案更多的解釋:

假設表reportreport_id爲PK缺乏inforamtion的。

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; 

LEFT JOIN確保你得到一個結果,即使data爲空或空或JSON數組爲空。

對於從單列在基礎表的總和,這是更快的:

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的好處(除了你的應用程序似乎需要它,就像你添加的那樣)。

+0

我聽到你正常化。我採用這種方法的原因是因爲該項目要求用戶可以上傳任何csv文檔,而不管結構如何以及列中包含哪些列。我只是以此AdWords報告爲例。 – 2015-03-19 15:42:01

+0

另外,謝謝你指出缺乏細節。我將編輯該問題。 – 2015-03-19 15:42:50

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[]。如果你的意思是data是一個json數組,你應該可以使用json_array_elements而不是unnest

+0

'unnest()'只能應用於Postgres數組。不是'json'或'jsonb'類型中的JSON數組。 – 2015-03-19 15:20:35

+0

該數組實際上是jsonb類型。我會嘗試json_array_elements。 – 2015-03-19 15:37:41

+1

@AdamKolkman:或'jsonb'的'jsonb_array_elements'。 – 2015-03-19 22:38:07