Postgresql-9.3:从不严格的json中提取数据

时间:2014-04-18 22:52:51

标签: sql json postgresql

我可以从非严格的JSON中提取所选字段吗?

我的表是:

CREATE TABLE testme (id integer primary key, b json not null);

INSERT INTO testme(id,b) values (1,'{"similarartists":{"artist":[{"name":"x"},{"name":"y"}],"@attr":{"artist":"2H Company"}}}');

INSERT INTO testme(id,b) values (2,'{"similarartists":{"artist":{"name":"z"},"@attr":{"artist":"2H Company"}}}');

INSERT INTO testme(id,b) values (3,'{"similarartists":{"artist":"junk string","@attr":{"artist":"2H Company"}}}');

我的第一个想法是:

SELECT json_array_elements(b->'similarartists'->'artist')->'name' FROM testme;

但这是错误的。

1 个答案:

答案 0 :(得分:1)

心理直觉告诉我,你的意思是当JSON结构对于表中的每一行都不统一时如何提取特定字段。

您发布的查询对示例中的任何行都无效,因为它们都没有在“similarartists”属性中有数组。但是,此查询至少对第1行有效:

SELECT json_array_elements(b->'similarartists'->'artist')->name 
FROM testme where id=1;

在另外两行中 - 第一行包含一个相似的艺术家,另一行包含标量(“垃圾字符串”)。所以,我猜想(再次是通灵力量)想要你想做的就是:

  1. 如果该行构成一个艺术家数组,则单独检索这些
  2. 如果该行包含单个艺术家,则检索此
  3. 否则忽略该行
  4. 使用9.3中提供的JSON支持,这是非常难以做到的。似乎没有一种简单的方法来推断JSON结构中数组元素属性的JSON类型。我在这里提出的解决方案似乎有效,但它远非优雅:

    SELECT CASE substring((b->'similarartists'->'artist')::text,1,1)
        WHEN '[' THEN json_array_elements(b->'similarartists'->'artist')->>'name'
        WHEN '{' THEN b->'similarartists'->'artist'->>'name'
        ELSE NULL
      END AS artist
    FROM testme;
    

    SqlFiddle

    查询正在检查提取的艺术家字段的字符串版本,以查看它是否以'[','{'或两者都没有。如果'''是一个艺术家阵列,你可以使用json_array_elements。如果它是'{'那么它就是一个艺术家。否则,它是垃圾,查询替换为NULL。当然,如果需要,你可以使用WHERE子句完全删除垃圾行。