2014-08-27 37 views
1

我有一個postgres表是JSON數據的陣列的字符串表示,像這樣一些數據:找元件的平均值在JSON數據的陣列的列中的Postgres

[ 
    {"UsageInfo"=>"P-1008366", "Role"=>"Abstract", "RetailPrice"=>2, "EffectivePrice"=>0}, 
    {"Role"=>"Text", "ProjectCode"=>"", "PublicationCode"=>"", "RetailPrice"=>2}, 
    {"Role"=>"Abstract", "RetailPrice"=>2, "EffectivePrice"=>0, "ParentItemId"=>"396487"} 
] 

這是是來自數據庫中單個相似數據列的一個單元格中的數據。

存儲在db中的數據類型是varchar(max)。

我的目標是找到具有「Role」=>「Abstract」的每個json項目的平均RetailPrice,包括數組中的所有json元素以及數據庫中的所有行。

喜歡的東西:

SELECT avg(json_extract_path_text(json_item, 'RetailPrice')) 
FROM (
    SELECT cast(json_items to varchar[]) as json_item 
    FROM my_table 
    WHERE json_extract_path_text(json_item, 'Role') like 'Abstract' 
) 

現在,很明顯這個特定的查詢將不會有幾個原因的工作。 Postgres不允許你直接將varchar轉換爲varchar []。即使在我有一個數組之後,這個查詢也不會遍歷數組。可能還有其他問題,但我希望它能幫助澄清我想得到的結果。

有關如何從數據庫中的所有這些json數據數組中獲取平均零售價的建議?

+0

這是很難的,因爲[紅移呢似乎沒有支持'generate_series()'當涉及表](http://stackoverflow.com/questions/22759980/generate-series-in-redhsift)。如果你每行有固定數量的json數組元素或者至少有一個小的最大值,你可以即興創建... – 2014-08-27 22:26:39

+0

另外我會期望'{「UsageInfo」:「P-1008366」...'而不是'{「 UsageInfo「=>」P-1008366「...'(':'而不是'=>')爲有效的json。 – 2014-08-27 22:40:37

+0

@Clodoaldo:我重新打開了這個。 *不是*重複,因爲這是用於Amazon Redshift並需要不同的解決方案。 – 2014-08-27 23:02:20

回答

1

似乎Redshift本身不支持json數據類型。至少,I found nothing in the online manual.

但是我發現了幾個JSON function in the manual,這應該是器樂:

JSON_ARRAY_LENGTH 
JSON_EXTRACT_ARRAY_ELEMENT_TEXT 
JSON_EXTRACT_PATH_TEXT 

由於generate_series()不支持,我們必須要替換...

SELECT tbl_id 
    , round(avg((json_extract_path_text(elem, 'RetailPrice'))::numeric), 2) AS avg_retail_price 
FROM (
    SELECT *, json_extract_array_element_text(json_items, pos) AS elem 
    FROM (VALUES (0),(1),(2),(3),(4),(5)) a(pos) 
    CROSS JOIN tbl 
    ) sub 
WHERE json_extract_path_text(elem, 'Role') = 'Abstract' 
GROUP BY 1; 
  • 我用一個窮人的解決方案代替:一個從0到n(VALUES表達式)的虛擬表。確保您數組達到陣列中可能元素的最大數量。如果您需要定期創建numbers表格。

  • 現代Postgres有更好的選擇,比如json_array_elements(),以非常好的json陣列。比較你的兄弟姐妹的問題Postgres的:

我在Postgres的測試與related operator ->>,它的工作原理:
SQL Fiddle.