【问题标题】:Get specific values from a jsonb column从 jsonb 列中获取特定值
【发布时间】:2020-02-02 12:05:24
【问题描述】:

我有一张桌子Customer

  • customerId(int)
  • 客户名称(字符串)
  • customerOrders(jsonB)

customerOrders 具有以下结构:

{ 
 "nodeValue":[
   { 
      "key": "key1",
      "value": "value1"
   },
   { 
      "key": "key2",
      "value": "value2"
   },
   { 
      "key": "key3",
      "value": "value3"
   },
   { 
      "key": "key4",
      "value": "value4"
   },
   { 
      "key": "key5",
      "value": "value5"
   }
 ]
}

我正在尝试获取key = 'key3' AND key = 'key4' 行中nodeValue 的值。

例如:返回'key3'和'key4'的值,WHERE key = 'key3' AND key = 'key4'

我正在尝试做类似的事情:

SELECT value, value 
from public.customers 
where nodeValue.key3 = 'key3' 
  AND nodeValue.key4 = 'key4'

【问题讨论】:

  • key = key3 AND Key = Key4 不可能发生。你是说OR吗?
  • 不,这两个条件都应该为真。
  • 单个key 变量不能同时具有值​​'key3''Key4'
  • 你的意思是像key3 = 'value3' AND key4 = 'value4'这样的吗?
  • 据我所知,Bergi 绝对正确

标签: sql json postgresql jsonb


【解决方案1】:
with orders as 
(
   select jsonb_array_elements(customerOrders->'nodeValue') as orders
   from customers
) 
select orders->'value' as val 
from orders 
where 
    orders->>'key' = 'key3' 
or  orders->>'key' = 'key4';

结果:

值1

值2

请注意使用操作符 ->> 来获取文本的值

db-fiddle

【讨论】:

  • 感谢您的回答。但我正在寻找类似的东西:{ key = "abs", value = "1"}, {key = "sup", value = "1"}, { key = "may", value = "2"}。我想查询类似: SELECT value, value from customers WHERE key = "abs" AND key = "sup";
    结果应该有2个值:1, 1
【解决方案2】:

获取key = 'key3' AND key = 'key4'所在行的nodeValue的值。

最好使用jsonb "contains" operator @>

SELECT customerid, customerOrders->'nodeValue'
FROM   customer
WHERE  customerOrders->'nodeValue' @> '[{"key": "key3"}]'
AND    customerOrders->'nodeValue' @> '[{"key": "key4"}]';

为了使其 快速 为大表提供索引支持。理想情况下是jsonb_path_ops 索引:

CREATE INDEX customer_nodeValue_idx ON customer
USING gin ((customerOrders->'nodeValue') jsonb_path_ops);  -- parentheses required

见:

你的问题的更高版本有点棘手:

返回'key3'和'key4'的

SELECT c.customerid, o.values
FROM   customer c
CROSS  JOIN LATERAL (
   SELECT ARRAY(
      SELECT o.ord->>'value'
      FROM   jsonb_array_elements(c.customerOrders->'nodeValue') o(ord)
      WHERE (o.ord->>'key' = 'key3' OR
             o.ord->>'key' = 'key4')
      )
   ) o(values)
WHERE  c.customerOrders->'nodeValue' @> '[{"key": "key3"}]'
AND    c.customerOrders->'nodeValue' @> '[{"key": "key4"}]';

首先过滤符合条件的行,如上(使用快速索引查找)。然后取消嵌套 JSON 文档并在 LATERAL 子查询中构建您的答案。应该是最简单、最干净和最快的。有关该技术,请参阅:

我在两个查询的结果中添加了customerid 以识别行。这是可选的。

dbfiddle here(同时演示)

设计

您可以将臃肿的 JSON 布局简化为:

'{
    "key1": "value1",
    "key2": "value2",
    "key3": "value3",
    "key4": "value4",
    "key5": "value5"
}'

或者至少:

'[
    {
        "key1": "value1"
    },
    {
        "key2": "value2"
    },
    {
        "key3": "value3"
    },
    {
        "key4": "value4"
    },
    {
        "key5": "value5"
    }
]'

将使一切变得更简单、更小、更快。

【讨论】:

    【解决方案3】:

    我怀疑你真正想要的是

    SELECT
      (SELECT orders->>'value'
        FROM json_array_elements(customerOrders->'nodeValue') AS orders
        WHERE orders->>'key' = 'key3'
      ) AS value_key3,
      (SELECT orders->>'value'
        FROM json_array_elements(customerOrders->'nodeValue') AS orders
        WHERE orders->>'key' = 'key4'
      ) AS value_key4
    FROM public.customers;
    

    但实际上您的数据结构不适合此目的。使用具有键和值作为属性的对象,而不是具有键值对的数组。这样,您可以轻松访问结果

    SELECT
      customerOrders->'nodeValue'->>'key3' AS value_key3,
      customerOrders->'nodeValue'->>'key4' AS value_key4
    FROM public.customers;
    

    【讨论】:

      【解决方案4】:

      首先你需要创建一个类型(或表)

      CREATE TYPE key_value_type AS (
          key text,
          value text
      );
      

      然后就可以使用jsonb_populate_recordset函数了

      SELECT
          r_key1.value AS key1,
          r_key2.value AS key2
      FROM
          customers c
          JOIN LATERAL jsonb_populate_recordset(NULL::key_value_type, customerOrders -> 'nodeValue') r_key1 
            ON r_key1.key = 'key1'
          JOIN LATERAL jsonb_populate_recordset(NULL::key_value_type, customerOrders -> 'nodeValue') r_key2 
            ON r_key2.key = 'key2'
      

      或者使用jsonb_to_recordset 函数(不创建类型)

      SELECT
          r_key1.value AS key1,
          r_key2.value AS key2
      FROM
          customers c
          JOIN LATERAL jsonb_to_recordset(customerOrders -> 'nodeValue') AS r_key1 (key text,
              value text) ON r_key1.key = 'key1'
          JOIN LATERAL jsonb_to_recordset(customerOrders -> 'nodeValue') AS r_key2 (key text,
              value text) ON r_key2.key = 'key2'
      

      这是两种选择的结果;

      | key1   | key2   |
      | ------ | ------ |
      | value1 | value2 |
      

      【讨论】:

      • 感谢您的回答,我的输出可以返回记录数组。
      猜你喜欢
      • 2019-01-23
      • 1970-01-01
      • 1970-01-01
      • 2023-02-01
      • 2016-03-09
      • 1970-01-01
      • 2021-09-11
      • 2018-03-11
      • 2020-05-21
      相关资源
      最近更新 更多