據(jù)提取實(shí)戰(zhàn):json_extract_path 與路徑提取函數(shù)全解(TIL))
文檔教程知識(shí)庫(kù)【免費(fèi)下載鏈接】til:memo: Today I Learned項(xiàng)目地址https://gitcode.com/gh_mirrors/ti/til點(diǎn)擊查看免費(fèi)下載導(dǎo)讀本文圍繞 TIL 倉(cāng)庫(kù)中 postgres/extracting-nested-json-data.md 記錄的實(shí)戰(zhàn)經(jīng)驗(yàn)系統(tǒng)講解如何在 PostgreSQL 的 JSON 列中按路徑一次性取出深層嵌套值。你將掌握json_extract_path/jsonb_extract_path及其文本版本的使用方法、#/#運(yùn)算符的等價(jià)寫(xiě)法、變長(zhǎng)路徑參數(shù)與數(shù)組下標(biāo)的細(xì)節(jié)并了解與提取配合的類(lèi)型判斷、美化輸出等配套技巧。場(chǎng)景JSON 列里存了嵌套數(shù)據(jù)在 PostgreSQL 中把 JSON 數(shù)據(jù)整體存進(jìn)一列是很常見(jiàn)的做法——訂單、配置、用戶資料等結(jié)構(gòu)化程度較低的數(shù)據(jù)都可以直接以 JSON 形式落庫(kù)。但當(dāng)業(yè)務(wù)代碼需要訪問(wèn)這些 JSON 內(nèi)部的具體字段時(shí)麻煩就來(lái)了。比如下面的owner字段頂層是一個(gè)對(duì)象license又是一個(gè)嵌套對(duì)象真正的目標(biāo)值number藏在了第三層owner -------------------------------------------------------------------------------- { name: Jason Borne, license: { number: T1234F5G6, state: MA } }如果數(shù)據(jù)庫(kù)代碼需要拿到駕照號(hào)T1234F5G6該如何編寫(xiě)查詢這正是原 TIL 要解決的第一個(gè)問(wèn)題如何從嵌套 JSON 中按路徑取值。為什么單靠-運(yùn)算符不夠用熟悉 PostgreSQL JSON 的人第一反應(yīng)通常是-運(yùn)算符。它的作用是按鍵取字段但一次只能向下取一層-- 取到 license 對(duì)象 select owner - license from some_table; -- 還需要再鏈一層才能到 number select owner - license - number from some_table;也就是說(shuō)面對(duì)兩層以上的嵌套-必須不斷鏈?zhǔn)狡唇觨wner-license-number。路徑層級(jí)越深表達(dá)式越長(zhǎng)越啰嗦更麻煩的是當(dāng)路徑本身是動(dòng)態(tài)的——例如路徑片段來(lái)自變量、來(lái)自代碼拼接、或已經(jīng)存放在一個(gè)text[]數(shù)組里——這種鏈?zhǔn)綄?xiě)法就難以應(yīng)付。這正是原 TIL 的核心結(jié)論僅靠-運(yùn)算符派不上用場(chǎng)需要改用json_extract_path函數(shù)由函數(shù)接收完整路徑作為參數(shù)一次調(diào)用直達(dá)目標(biāo)。核心函數(shù)json_extract_path 一次性提取嵌套值json_extract_path屬于 PostgreSQL 的 JSON 處理函數(shù)第一個(gè)參數(shù)是 JSON 文檔后面的參數(shù)依次是路徑的每一層鍵名 select json_extract_path(owner, license, number) from some_table; json_extract_path ------------------- T1234F5G6與鏈?zhǔn)?不同json_extract_path把整條路徑作為可變長(zhǎng)參數(shù)列表傳入語(yǔ)義清晰、層級(jí)可控尤其適合路徑由程序動(dòng)態(tài)構(gòu)造的場(chǎng)景。其完整函數(shù)簽名對(duì)應(yīng)json類(lèi)型為json_extract_path(from_json json, VARIADIC path_elems text[])調(diào)用時(shí)傳入的license、number等字符串即被收集為一個(gè)text[]路徑數(shù)組。路徑不存在時(shí)的行為如果指定的路徑在 JSON 中不存在例如鍵拼寫(xiě)錯(cuò)誤、中間節(jié)點(diǎn)缺失json_extract_path會(huì)返回NULL而不是報(bào)錯(cuò)。這一點(diǎn)在數(shù)據(jù)清洗或防御性查詢中很有價(jià)值——可以在提取后配合COALESCE提供默認(rèn)值例如select coalesce(json_extract_path(owner, license, number), UNKNOWN) from some_table;json 與 jsonb四個(gè)提取函數(shù)對(duì)照原 TIL 的示例基于json類(lèi)型。實(shí)際開(kāi)發(fā)中更常見(jiàn)的是jsonb二進(jìn)制存儲(chǔ)、解析后的 JSONB 類(lèi)型它同樣有對(duì)應(yīng)的提取函數(shù)。四個(gè)函數(shù)形成一張完整的對(duì)照表函數(shù)輸入類(lèi)型返回類(lèi)型說(shuō)明json_extract_path(json, text[])jsonjson返回目標(biāo)值保持 JSON 類(lèi)型json_extract_path_text(json, text[])jsontext返回目標(biāo)值的純文本形式j(luò)sonb_extract_path(jsonb, text[])jsonbjsonb返回目標(biāo)值保持 JSONB 類(lèi)型jsonb_extract_path_text(jsonb, text[])jsonbtext返回目標(biāo)值的純文本形式使用規(guī)則與json版本完全一致-- jsonb 列同樣傳路徑 select jsonb_extract_path(owner, license, number) from some_table; -- 需要不帶引號(hào)的純文本 select jsonb_extract_path_text(owner, license, number) from some_table;返回類(lèi)型帶來(lái)的引號(hào)差異注意返回類(lèi)型的差別*_extract_path返回的是 JSON 類(lèi)型的值如果目標(biāo)是一個(gè) JSON 字符串客戶端展示時(shí)會(huì)帶上 JSON 的引號(hào)而*_extract_path_text直接返回text得到的就是T1234F5G6這樣的裸字符串。后續(xù)要把結(jié)果用于字符串拼接、比較或嵌入文本時(shí)優(yōu)先選用_text版本。為什么推薦 jsonb倉(cāng)庫(kù)中的 postgres/determine-types-of-jsonb-records.md 記錄了jsonb的實(shí)用背景jsonb列里可以存放對(duì)象、數(shù)組、字符串、數(shù)字、布爾、null 等多種值且存儲(chǔ)時(shí)已做解析訪問(wèn)和提取都更高效、更規(guī)范。如果業(yè)務(wù)從零開(kāi)始設(shè)計(jì)表結(jié)構(gòu)jsonb是更主流的選擇配合jsonb_extract_path系列函數(shù)即可完成同樣的嵌套提取。運(yùn)算符等價(jià)寫(xiě)法# 與 #如果你更喜歡運(yùn)算符風(fēng)格PostgreSQL 為路徑提取提供了#和#它們是json_extract_path的運(yùn)算符形態(tài)json與jsonb均支持-- 等價(jià)于 json_extract_path(owner, license, number) select owner # {license, number} from some_table; -- 等價(jià)于 json_extract_path_text(owner, license, number) select owner # {license, number} from some_table;區(qū)別與上面一致#返回 JSON 類(lèi)型#返回純文本。此時(shí)路徑以{license, number}這種文本數(shù)組字面量形式給出同樣適用于路徑先拼好、再傳入查詢的動(dòng)態(tài)場(chǎng)景。#與json_extract_path屬于同一套底層能力二者可以按代碼風(fēng)格任選。路徑參數(shù)進(jìn)階可變長(zhǎng)參數(shù)與數(shù)組下標(biāo)json_extract_path的VARIADIC簽名意味著兩件事可以逐個(gè)傳參json_extract_path(owner, license, number)與可以直接傳數(shù)組先構(gòu)造好路徑數(shù)組再展開(kāi)傳入例如-- 路徑來(lái)自一個(gè) text[] 數(shù)組 select json_extract_path(owner, variadic array[license, number]) from some_table;兩者等價(jià)適合在不同調(diào)用場(chǎng)景中選用。用數(shù)字字符串訪問(wèn)數(shù)組元素路徑中的鍵名是字符串但如果某一段要訪問(wèn)的是數(shù)組下標(biāo)直接把下標(biāo)寫(xiě)成字符串即可-- 假設(shè)字段形如 {tags: [a, b, c]} select json_extract_path(doc, tags, 1) from some_table; -- 返回 b1會(huì)被按數(shù)組下標(biāo)解釋從而支持對(duì) JSON 數(shù)組內(nèi)元素的定位提取。與嵌套對(duì)象鍵混合使用時(shí)規(guī)則同樣成立路徑中每一段要么是對(duì)象鍵要么是數(shù)組下標(biāo)。配套技巧與路徑提取搭配的 JSON 實(shí)戰(zhàn)嵌套提取只是 JSON 列處理的一環(huán)倉(cāng)庫(kù)中還有多篇 TIL 可以與它組合使用構(gòu)成完整的 JSON 數(shù)據(jù)處理工具箱判斷頂層值類(lèi)型提取之前先用 postgres/determine-types-of-jsonb-records.md 記錄的jsonb_typeof(my_jsonb_column)確認(rèn)目標(biāo)到底是對(duì)象、數(shù)組還是標(biāo)量避免對(duì)路徑形態(tài)做錯(cuò)誤假設(shè)。美化查看整行嵌套 JSON 默認(rèn)在一行里擠成一團(tuán)難以閱讀用 postgres/pretty-printing-jsonb-rows.md 中的jsonb_pretty(...)可以展開(kāi)成縮進(jìn)格式便于肉眼核對(duì)提取結(jié)果的上下文。寫(xiě)入含引號(hào)/特殊字符的 JSON往測(cè)試表里灌 JSON 數(shù)據(jù)時(shí)postgres/label-dollar-quoted-strings-with-a-tag.md 與 postgres/escaping-string-literals-with-dollar-quoting.md 記錄的美元引用如$JSON$...$JSON$::jsonb可以免去轉(zhuǎn)義煩惱。查詢可用運(yùn)算符全集想了解jsonb還能配合哪些運(yùn)算符如包含關(guān)系可用 postgres/show-all-versions-of-an-operator.md 中的\do 在 psql 里直接列出其全部參數(shù)類(lèi)型組合。版本與適用前提json類(lèi)型自 PostgreSQL 9.2 起可用jsonb自 9.4 起可用json_extract_path/json_extract_path_text及#/#運(yùn)算符自 9.3 起提供jsonb_extract_path/jsonb_extract_path_text隨 9.4 的jsonb一并提供。原 TIL 引用的文檔即為 9.4 版本。本文示例均沿用原 TIL 的json列寫(xiě)法若你的表使用jsonb列請(qǐng)對(duì)應(yīng)改用jsonb_extract_path系列函數(shù)參數(shù)用法完全一致。小結(jié)面對(duì) PostgreSQL JSON 列中的多層嵌套數(shù)據(jù)json_extract_path提供了一條直達(dá)路徑的提取方式函數(shù)簽名直觀、支持變長(zhǎng)參數(shù)與數(shù)組下標(biāo)、路徑缺失時(shí)安全返回NULL。配合_text版本去除引號(hào)、#/#運(yùn)算符切換寫(xiě)法以及倉(cāng)庫(kù)內(nèi)其他 JSON 相關(guān) TIL 的配套技巧足以覆蓋從存 JSON到取嵌套值的完整開(kāi)發(fā)場(chǎng)景。贊分享文檔教程知識(shí)庫(kù)【免費(fèi)下載鏈接】til:memo: Today I Learned項(xiàng)目地址https://gitcode.com/gh_mirrors/ti/til點(diǎn)擊查看免費(fèi)下載相關(guān)推薦Apache Druid SQL JSON 函數(shù)完全指南解析、提取、轉(zhuǎn)換與構(gòu)造嵌套數(shù)據(jù)Apache Druid SQL JSON 函數(shù)完全指南解析、提取、轉(zhuǎn)換與構(gòu)造嵌套數(shù)據(jù) Druid 通過(guò)內(nèi)建的 SQL JSON 函數(shù)族支持對(duì) COMPLEX數(shù)據(jù)庫(kù)OLAP大數(shù)據(jù)后端YOLOv8實(shí)時(shí)目標(biāo)檢測(cè)與AI輔助瞄準(zhǔn)系統(tǒng)架構(gòu)設(shè)計(jì)YOLOv8實(shí)時(shí)目標(biāo)檢測(cè)與AI輔助瞄準(zhǔn)系統(tǒng)架構(gòu)設(shè)計(jì) 技術(shù)架構(gòu)概述與核心實(shí)現(xiàn)原理 YOLOv8自瞄系統(tǒng)是一個(gè)基于深度學(xué)習(xí)目標(biāo)檢測(cè)技術(shù)的實(shí)時(shí)計(jì)算機(jī)視覺(jué)應(yīng)用專為FP人工智能計(jì)算機(jī)視覺(jué)游戲開(kāi)發(fā)draw.io 桌面版 Windows 安裝完整指南免費(fèi)離線繪圖工具一次搞定draw.io 桌面版 Windows 安裝完整指南免費(fèi)離線繪圖工具一次搞定 drawio desktop 是 draw.io 官方出品的桌面端基于 Ele數(shù)據(jù)庫(kù)OLAP數(shù)據(jù)倉(cāng)庫(kù)大數(shù)據(jù)湖倉(cāng)一體數(shù)據(jù)分析創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考