如何保留jsonb数组成员的数据类型?
问题描述
我有如下简单查询:
select jsonb_path_query_first(a,'$[0]') from (values (jsonb_build_array(1, 2, 3))) as "t" ("a")
该查询可正常运行,但返回的是jsonb类型,而我期望得到整数类型,jsonb数组似乎丢失了成员的类型。
请问是否有办法让jsonb识别成员类型,以便访问时直接获取对应类型?因为手动转换会增加不必要的复杂度。
例如以下查询不手动转换则无法编译:
select jsonb_path_query_first(a,'$[0]')+1 from (values (jsonb_build_array(1, 2, 3))) as "t" ("a")
解决方案
PostgreSQL 中 jsonb_path_query_first 这类 JSON 路径函数的设计目标就是返回 jsonb 类型——因为路径查询可能匹配不同类型的 JSON 值,函数无法提前确定要返回的 SQL 原生类型,所以必须显式转换才能得到整数这类原生类型。不过可以通过以下方式简化操作,减少手动转换的繁琐:
- 针对简单数组索引使用更简洁的操作符
如果只是获取数组的指定下标元素,用->操作符配合类型转换会比路径函数更直接:
select (a->0)::int + 1 from (values (jsonb_build_array(1, 2, 3))) as t(a);
这里 a->0 返回对应位置的 jsonb 元素,::int 是显式转换为整数类型,语法比完整的路径函数更简洁。
- 封装自定义函数复用转换逻辑
如果需要频繁使用路径查询并转换为整数,可以创建一个自定义函数封装转换逻辑,避免重复写类型转换:
create or replace function jsonb_path_get_int(jsonb_val jsonb, path text) returns integer as $$ select jsonb_path_query_first(jsonb_val, path)::integer; $$ language sql immutable;
之后就可以直接调用这个函数,无需每次手动转换:
select jsonb_path_get_int(a, '$[0]') + 1 from (values (jsonb_build_array(1, 2, 3))) as t(a);
- 利用隐式转换简化写法
如果使用->>操作符获取文本形式的元素,PostgreSQL 在进行算术运算时会自动隐式转换为数值类型:
select (a->>0) + 1 from (values (jsonb_build_array(1, 2, 3))) as t(a);
注意:这种隐式转换仅适用于确定元素是数值类型的场景,若元素可能是其他类型,可能会抛出转换错误。
需要明确的是,JSONB 本身并没有丢失成员类型——你可以用 jsonb_typeof(a->0) 验证元素类型确实是 number,只是路径函数返回的是 JSONB 容器,必须提取出里面的原生值才能进行 SQL 原生类型的运算。
内容的提问来源于stack exchange,提问作者Takis
相关产品推荐
相关产品推荐

