如何用运算符提取仅含单个键的JSONB对象的键(替代表函数jsonb_each)
如何用运算符提取仅含单个键的JSONB对象的键(替代表函数jsonb_each)
嘿,我完全懂你觉得用jsonb_each这种表函数处理单键JSONB对象有多啰嗦——就像拿大象拍苍蝇,完全没必要!下面给你几个更清爽的方法来提取那个唯一的键,还能直接用到你的函数里大幅简化代码~
核心提取方法(替代表函数)
针对仅含单个键的JSONB对象,你可以用以下两种简洁方式提取键,完全不用依赖jsonb_each这类表函数:
方法1:标量子查询提取键
利用jsonb_object_keys的标量返回特性,PostgreSQL会自动将单结果子查询作为标量值返回:
(SELECT key FROM jsonb_object_keys(你的单键JSONB对象))
对应的提取该键的值,用你之前想到的路径运算符就可以:
你的单键JSONB对象 #>> '{$.*}'
{$.*}会匹配对象的所有值,因为只有一个键,所以直接返回对应的值。
方法2:JSON路径查询(PostgreSQL 12+支持)
用JSON路径语法直接获取唯一键,写法更紧凑:
jsonb_path_query_first(你的单键JSONB对象, 'keys($)') #>> '{}'
keys($)会返回对象的所有键组成的JSON数组jsonb_path_query_first取数组的第一个(也是唯一一个)元素#>> '{}'将JSONB类型的键转换为普通文本
简化你的jreduxseq_to_text函数
基于上面的方法,我们可以完全删掉原来那堆繁琐的LATERAL+UNION代码,让函数逻辑更清晰:
CREATE or replace FUNCTION jreduxseq_to_text( p_list jsonb, p_level int default 1, p_max_level int default 3 ) RETURNS TABLE( level integer, ordinality bigint, prefix text, suffixes jsonb, is_prefix boolean ) AS $f$ SELECT p_level, t.ordinality, CASE WHEN t.is_prefix THEN (SELECT key FROM jsonb_object_keys(t.value)) ELSE t.value #>> '{}' END as prefix, CASE WHEN t.is_prefix THEN t.value #>> '{$.*}'::text[] ELSE NULL END as suffixes, t.is_prefix FROM ( SELECT ordinality, value, jsonb_typeof(value)='object' AS is_prefix FROM jsonb_array_elements(p_list) WITH ORDINALITY ) t $f$ LANGUAGE SQL IMMUTABLE;
简化说明
- 当元素是单键JSONB对象(
t.is_prefix = true):- 用标量子查询
(SELECT key FROM jsonb_object_keys(t.value))直接提取唯一键作为prefix - 用
#>> '{$.*}'提取该键对应的JSONB值作为suffixes
- 用标量子查询
- 当元素是普通字符串时,逻辑和原来保持一致
- 彻底移除了原来需要处理空对象、UNION拼接的冗余代码,结构清爽很多
你可以测试一下这个简化后的函数,和原函数的输出结果完全一致,但是代码复杂度直接降了一个等级,再也不用为了取一个键写一堆表函数逻辑啦!




