【问题标题】:Is there any way to search in json postgres column using matching clause?有没有办法使用匹配子句在 json postgres 列中搜索?
【发布时间】:2020-06-13 20:07:50
【问题描述】:

我正在尝试从 Postgres JSON 列中搜索记录。存储的数据有一个结构是这样的

{
  "contract_shipment_date": "2015-06-25T19:00:00.000Z",
  "contract_product_grid": [
    {
      "product_name": "Axele",
      "quantity": 22.58
    },
    {
      "product_name": "Bell",
      "quantity": 52.58
    }
  ],
  "lc_status": "Awaited" 
}

我的表名是 Heap,列名是 contract_product_grid。此外,contract_product_grid 列可以包含多个产品记录。 我找到了此文档,但无法获得所需的输出。

需要的情况是,我有一个过滤器,用户可以在其中选择product_name,并在输入名称的基础上使用匹配子句,获取记录并返回给用户。

【问题讨论】:

  • 看一下文档,很清楚。也看看这个例子,和你的问题很相似:postgresqltutorial.com/postgresql-json
  • 您想要完全匹配(使用=)还是通配符匹配(使用LIKE
  • 使用通配符(Like、In 等)

标签: sql json postgresql


【解决方案1】:

假设您输入Axele 作为product_name 输入,并希望返回quantity 键的匹配值。

然后使用:

SELECT js2->'quantity' AS quantity
  FROM
  (
   SELECT JSON_ARRAY_ELEMENTS(value::json) AS js2
     FROM heap,
     JSON_EACH_TEXT(contract_product_grid) AS js
    WHERE key = 'contract_product_grid' 
  ) q
  WHERE js2->> 'product_name' = 'Axele' 

其中将最外层的JSON通过JSON_EACH_TEXT(json)扩展成key&value对,并通过JSON_ARRAY_ELEMENTS(value::json)函数将所有元素与新形成的数组分开。

然后,在主查询中通过特定的product_name 过滤掉。

Demo

附言不要忘记用花括号将 JSON 列的值包裹起来

【讨论】:

  • 谢谢你,但它给出了以下错误:错误:无法将数组解构为对象
  • 您的 DBMS 版本是什么@MuhammadIsrarShahid?你看过演示吗?
【解决方案2】:

您需要取消嵌套数组才能对每个值使用 LIKE 条件:

select h.*
from heap h
where exists (select * 
              from jsonb_array_elements(h.contract_product_grid -> 'contract_product_grid') as p(prod)
              where p.prod ->> 'product_name' like 'Axe%')

如果您真的不需要通配符搜索(所以= 而不是LIKE),您可以使用更高效的包含运算符@>

select h.*
from heap h
where h.contract_product_grid -> 'contract_product_grid' @> '[{"product_name": "Axele"}]';

这也可以用来搜索多个产品:

select h.*
from heap h
where h.contract_product_grid -> 'contract_product_grid' @> '[{"product_name": "Axele"}, {"product_name": "Bell"}]';

如果您使用的是 Postgres 12,您可以使用 JSON path 表达式简化一下:

select *
from heap
where jsonb_path_exists(contract_product_grid, '$.contract_product_grid[*].product_name ? (@ starts with "Axe")')

或者使用正则表达式:

select *
from heap
where jsonb_path_exists(contract_product_grid, '$.contract_product_grid[*].product_name ? (@ like_regex "axe.*" flag "i")')

【讨论】:

    【解决方案3】:

    SELECT * FROM ( SELECT JSON_ARRAY_ELEMENTS(contract_product_grid::json) AS js2 FROM heaps WHERE 'contract_product_grid' = 'contract_product_grid' ) q WHERE js2->> 'product_name' IN ('Axele', 'Bell') 正如我在问题中提到的那样,我的列名是“contract_product_grid”,我只需要从中进行搜索。 使用此查询,我可以使用带有输入产品名称的 IN 子句获取 contract_product_grid 信息。

    【讨论】:

    • 但这不使用通配符。如果您不需要使用@> 运算符进行通配符搜索,效率会更高。
    猜你喜欢
    • 2022-08-12
    • 2018-02-17
    • 1970-01-01
    • 2022-08-15
    • 1970-01-01
    • 1970-01-01
    • 2021-02-21
    • 2018-04-17
    相关资源
    最近更新 更多