查询具有不同数据类型的 PostgreSQL JSONB 列
Querying PostgreSQL JSONB column with varying types for data
作为我的 PostgreSQL 数据库中模式的一部分,目前 运行ning 版本 11,但如果它解除阻塞则愿意升级:我有一个 jsonb 列 data
,其中包含各种嵌套对象跨行的结构,我无法控制。例如:
第 1 行可能是:{'rootProperty': { 'nestedProperty': 'someStrVal' }}
第 2 行可能具有类似的架构:{'rootProperty': { 'nestedProperty': 2, 'otherNestedProperty': 'someOtherString' }}
当我尝试根据 jsonb 列中具有不同类型的 属性 查询 row/subset 行时,我遇到了困难。在此示例中,nestedProperty
是第 1 行中的字符串和第 2 行中的整数。
当我尝试 运行 查询
SELECT * FROM TABLE WHERE data -> 'rootProperty' ->> 'nestedProperty' = 'someStrVal'
事情 运行 很好,但如果我尝试
SELECT * FROM TABLE WHERE data -> 'rootProperty' ->> 'nestedProperty' > 1
或
SELECT * FROM TABLE WHERE (data -> 'rootProperty' ->> 'nestedProperty')::int > 1
查询错误,分别为 'operator does not exist: text > integer' 和 'invalid input syntax for integer: "someStrVal"'。
有没有一种方法可以使 jsonb 列具有可变模式,这些模式可能具有重叠的结构,尽管数据类型不同,但仍然可以查询所有这些模式?我不介意必须指定我要查找的类型,只要它可以跳过或绕过不符合该类型标准的行即可。
相同的 属性 具有不同类型的值开始时似乎很奇怪,但很可能您无法更改该“设计”。
Postgres 12 引入了对 SQL/JSON path 表达式的支持,它对数据类型转换很宽松,如果您尝试将 someStrVal
与数字进行比较,也不会出错。
查询:
select *
from the_table
where data @@ '$.rootProperty.nestedProperty > 1'
return 所有 nestedProperty
为有效数字的行都将大于 1。无法转换为数字的值将被静默忽略。
也可以写成:
where jsonb_path_exists(the_column, '$.rootProperty.nestedProperty ? (@ > 1)')
可以通过使用带有第三个参数的 jsonb_path_exists()
将值作为参数传递:
where jsonb_path_exists(the_column, '$.rootProperty.nestedProperty ? (@ > $nr)', '{"nr": 1}')
最后一个参数可以通过参数占位符传递,例如在 Java:
where jsonb_path_exists(the_column, '$.rootProperty.nestedProperty ? (@ > $nr)', cast(? as jsonb))
然后:
PreparedStatement pstmt = conn.prepareStatement(...);
pstmt.setString(1, "{\"nr\": 1}");
我不记得具体是在哪个版本中引入的,但是您可以使用 json_typeof
函数和 CASE
表达式将 属性 的值转换为正确的类型.我会使用 SQL 函数来保持我的查询整洁干净:
CREATE FUNCTION jsonb_to_integer(jsonb, text) RETURNS integer AS
$$
SELECT CASE jsonb_typeof(->)
WHEN 'number' THEN (->>)::integer
ELSE null
END
$$
LANGUAGE SQL
STABLE
RETURNS NULL ON NULL INPUT;
然后就是:
SELECT * FROM TABLE WHERE jsonb_to_integer(data, 'rootProperty') > 1;
作为我的 PostgreSQL 数据库中模式的一部分,目前 运行ning 版本 11,但如果它解除阻塞则愿意升级:我有一个 jsonb 列 data
,其中包含各种嵌套对象跨行的结构,我无法控制。例如:
第 1 行可能是:{'rootProperty': { 'nestedProperty': 'someStrVal' }}
第 2 行可能具有类似的架构:{'rootProperty': { 'nestedProperty': 2, 'otherNestedProperty': 'someOtherString' }}
当我尝试根据 jsonb 列中具有不同类型的 属性 查询 row/subset 行时,我遇到了困难。在此示例中,nestedProperty
是第 1 行中的字符串和第 2 行中的整数。
当我尝试 运行 查询
SELECT * FROM TABLE WHERE data -> 'rootProperty' ->> 'nestedProperty' = 'someStrVal'
事情 运行 很好,但如果我尝试
SELECT * FROM TABLE WHERE data -> 'rootProperty' ->> 'nestedProperty' > 1
或
SELECT * FROM TABLE WHERE (data -> 'rootProperty' ->> 'nestedProperty')::int > 1
查询错误,分别为 'operator does not exist: text > integer' 和 'invalid input syntax for integer: "someStrVal"'。
有没有一种方法可以使 jsonb 列具有可变模式,这些模式可能具有重叠的结构,尽管数据类型不同,但仍然可以查询所有这些模式?我不介意必须指定我要查找的类型,只要它可以跳过或绕过不符合该类型标准的行即可。
相同的 属性 具有不同类型的值开始时似乎很奇怪,但很可能您无法更改该“设计”。
Postgres 12 引入了对 SQL/JSON path 表达式的支持,它对数据类型转换很宽松,如果您尝试将 someStrVal
与数字进行比较,也不会出错。
查询:
select *
from the_table
where data @@ '$.rootProperty.nestedProperty > 1'
return 所有 nestedProperty
为有效数字的行都将大于 1。无法转换为数字的值将被静默忽略。
也可以写成:
where jsonb_path_exists(the_column, '$.rootProperty.nestedProperty ? (@ > 1)')
可以通过使用带有第三个参数的 jsonb_path_exists()
将值作为参数传递:
where jsonb_path_exists(the_column, '$.rootProperty.nestedProperty ? (@ > $nr)', '{"nr": 1}')
最后一个参数可以通过参数占位符传递,例如在 Java:
where jsonb_path_exists(the_column, '$.rootProperty.nestedProperty ? (@ > $nr)', cast(? as jsonb))
然后:
PreparedStatement pstmt = conn.prepareStatement(...);
pstmt.setString(1, "{\"nr\": 1}");
我不记得具体是在哪个版本中引入的,但是您可以使用 json_typeof
函数和 CASE
表达式将 属性 的值转换为正确的类型.我会使用 SQL 函数来保持我的查询整洁干净:
CREATE FUNCTION jsonb_to_integer(jsonb, text) RETURNS integer AS
$$
SELECT CASE jsonb_typeof(->)
WHEN 'number' THEN (->>)::integer
ELSE null
END
$$
LANGUAGE SQL
STABLE
RETURNS NULL ON NULL INPUT;
然后就是:
SELECT * FROM TABLE WHERE jsonb_to_integer(data, 'rootProperty') > 1;