【问题标题】:How to get JSON values by index number using PostgerSQL?如何使用 PostgreSQL 通过索引号获取 JSON 值?
【发布时间】:2020-10-27 08:25:21
【问题描述】:

我有这个样本数据:

   ID          Name
    1     {'a':'content1'}
    1     {'b':'content1'}
    1     {'c':'content2'}
    1     {'d':'content2'}
    1     {'e':'content3'}
    1     {'f':'content3'}
    2     ['content4']
    2     ['content4']
    2     ['content5']
    2     ['content5']

ID : INT

名称:JSON

我想要这个结果

   ID       Name
    1     content1
    1     content1
    1     content2
    1     content2
    1     content3
    1     content3
    2     content4
    2     content4
    2     content5
    2     content5

通常,在处理JSON时,我总是使用::JSON ->> 'key'

但是,当ID = 1 时,名称列的key 变化很大。所以我想知道是否有任何方法可以在不专门调用 JSON 值的键的情况下获取值(内容)。

我真的不知道如何解决这个问题来提供我的尝试。

p/s:请仅使用 postgreSQL

版本:x86_64-pc-linux-gnu 上的 PostgreSQL 11.4 (Debian 11.4-1.pgdg90+1),由 gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516,64 位编译

【问题讨论】:

  • 如果您的 JSON 对象包含多个键或数组包含多个元素怎么办?
  • @a_horse_with_no_name,目前正在开发 Superset,数据已上传到 Superset,因此无法确定是哪个版本,数据由多个开发人员构建。是的,有些人拥有超过 1 个密钥。有什么建议或解决方案吗?
  • 是的,只有第一个,我已经在问题中包含了版本

标签: sql json postgresql


【解决方案1】:

如果需要处理多个键/数组元素,可以在提取键/元素时应用limit子句。

select t.id, o.content
from test t
  cross join lateral (
    (
      select content
      from jsonb_each_text(t.name) as e(key,content)
      where jsonb_typeof(t.name) = 'object'
      limit 1
    )
    union all
    (
      select *
      from jsonb_array_elements_text(t.name)
      where jsonb_typeof(t.name) = 'array'
      limit 1
    )
  ) o ;

请注意,limit 会选择任意元素,不能保证它是“第一个”元素,但很有可能。

要按索引选择元素,您可以使用:

select t.id, o.content
from test t
  cross join lateral (
    select e.content
    from jsonb_each_text(t.name) with ordinality as e(key,content,idx)
    where jsonb_typeof(t.name) = 'object'
      and e.idx = 1
    union all
    select e.element
    from jsonb_array_elements_text(t.name)  with ordinality as e(element,idx)
    where jsonb_typeof(t.name) = 'array'
     and e.idx = 1
  ) o ;

如果您的name 列定义为json(而不是应该是jsonb),那么您需要使用对应的json_xxx 函数(不是jsonb_xxx

Online example

【讨论】:

    【解决方案2】:

    您可以使用json_typeof() 来确定在横向连接中使用什么,json_each_text() 用于object 值或json_array_elements_text() 用于array 值,然后union 结果。

    select o.id, e.v as name
      from j_by_index o
           cross join lateral json_each_text(o.name) as e(k,v)
     where json_typeof(o.name) = 'object'
    union all
    select a.id, e.v
      from j_by_index a
           cross join lateral json_array_elements_text(a.name) as e(v)
     where json_typeof(a.name) = 'array';
    
    ┌────┬──────────┐
    │ id │   name   │
    ├────┼──────────┤
    │  1 │ content1 │
    │  1 │ content1 │
    │  1 │ content2 │
    │  1 │ content2 │
    │  1 │ content3 │
    │  1 │ content3 │
    │  2 │ content4 │
    │  2 │ content4 │
    │  2 │ content5 │
    │  2 │ content5 │
    └────┴──────────┘
    (10 rows)
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-13
      • 2013-12-05
      • 2011-04-27
      • 2019-10-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多