2014-08-27 55 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.