查找与数组 json 字段匹配的记录

问题描述 投票:0回答:1

我需要选择“类别”字段中至少有一个值的所有行。 “categories”字段的类型是 JSONB。

数据库中我的“类别”字段包含一个数字数组:

[20,23,24]

我正在尝试这个:

jsonb_exists_any( finishes.categories, ARRAY[20, 23] )

但我收到此错误:

ERROR: cannot cast type integer[] to json
LINE 5: AND jsonb_exists_any( categories, ARRAY[20, 23]::json )

如果我用字符串数组替换字段中的数据,效果很好。例如:

["20","23","24"]

然后:

jsonb_exists_any( finishes.categories, ARRAY['20', '23'] )

但这不是我想要达到的目标。

有什么提示吗?

postgresql jsonb postgresql-14
1个回答
0
投票

说明

jsonb_exists_any()
自 9.4 版本起在 Postgres 中实现。但它并不是面向用户的函数,只是为了实现
jsonb
运算符
?|
,您更愿意使用它:

SELECT jsonb '[20,23,24]' ?| '{20, 23}'::text[];  -- false (!)

仍然无法按照您想要的方式工作,因为操作员(如函数)回答了问题,引用了手册

文本数组中的任何字符串是否作为顶级键或数组元素存在?

注意术语“字符串”。 JSON 数组的元素是数字而不是字符串。考虑:

SELECT jsonb_typeof (jsonb '20')     -- number
     , jsonb_typeof (jsonb '"20"');  -- string

这就是将数组元素转换为字符串时的效果:

SELECT jsonb '["20", "23", "24"]' ?| '{20, 23}'::text[];  -- true

即使这个“有效”:

SELECT jsonb '[20, "23", 24, {"foo":"bar"}]' ?| '{20, 23}';  -- true

与 Postgres 数组不同,JSON 数组允许异构元素类型。
当运算符解析明确时,正确的操作数会自动强制为

text[]

相关:

解决方案

据我所知(在撰写本文时 Postgres 17)仍然没有完全简单的方法来匹配给定数组的 any 值。

解决方案包括:

jsonb
“包含”运算符
@>
ANY
构造
结合起来。
@>
期望右侧有一个
jsonb
值,因此您无法传递普通数组(如
int[]
numeric[]
):

SELECT jsonb '[20,23,24]' @> ANY (ARRAY [jsonb '[22]', jsonb '[23]']);

或者:

SELECT jsonb '[20,23,24]' @> ANY ((ARRAY ['[22]', '[23]'])::jsonb[]);

或者使用最少的语法:

SELECT jsonb '[20,23,24]' @> ANY ('{[22],[23]}');

(当运算符解析明确且输入未键入时,会自动强制右操作数。)

从 Postgres 12 开始,您还可以使用 jsonpath 运算符

@?
:

SELECT jsonb '[20,23,24]' @? '$[*] ? (@ == 22 || @ == 23)';

同样,没有合适的“重叠”运算符来检查整个数组或值列表,因此您必须将其拼写出来。

Postgres 数组 提供所需的功能。虽然都是数字,但您可以转换并使用 数组重叠运算符

&&
:

SELECT ARRAY(SELECT jsonb_array_elements_text(jsonb '[20,23,24]')::int) && '{22,23}'::int[];

...这提供了一系列的选择。参见:

相关:

更好的解决方案

如果数组就是全部,只需使用一个普通的 Postgres 数组开始,没有 JSON 包装器,你就可以了:

SELECT '{20,23,24}'::int[] && '{22,23}'::int[];
© www.soinside.com 2019 - 2024. All rights reserved.