精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

SQLite是文檔數據庫嗎?

數據庫
雖然 SQLite 是一個嵌入式數據庫,但是它支持 JSON 存儲,并且通過 JSON1 擴展插件提供了許多 JSON 函數和運算符;同時,SQLite 表達式索引(Indexes On Expressions)和生成列(Generated Column)為 JSON 數據提供了索引支持,從而實現了文檔存儲和處理功能。

雖然 SQLite 是一個嵌入式數據庫,但是它支持 JSON 存儲,并且通過 JSON1 擴展插件提供了許多 JSON 函數和運算符;同時,SQLite 表達式索引(Indexes On Expressions)和生成列(Generated Column)為 JSON 數據提供了索引支持,從而實現了文檔存儲和處理功能。

本文給大家介紹一下如何將 SQLite 作為一個文檔數據庫使用。

一個文檔存儲案例

我們首先來看一個簡單的案例:

sqlite> create table docs(
   ...> id int not null primary key,
   ...> content text
   ...> 
   
sqlite> insert into docs(id, content) 
   ...> values (1, json('{"name":"apple", "price":6.50}'));

首先,我們創建了一個測試表 docs;其中 content 字段用于存儲 JSON 文檔,字段類型為 TEXT。

然后,我們使用 json() 函數確保了輸入字符串符合 JSON 格式要求,如果參數不滿足 JSON 格式要求將會返回錯誤。例如:

sqlite> select json('"not a valid json string');
Error: malformed JSON

接下來我們可以在查詢中使用 JSON 文檔中的內容:

sqlite> select * from docs 
   ...> where json_extract(content, '$.name') = 'apple';
   
1|{"name":"apple","price":6.50}

json_extract() 函數用于從 JSON 文檔中返回 name 節點的數據,具體的函數介紹參考下文。

如果想要對以上查詢進行優化,可以使用表達式索引。例如:

sqlite> create index docs_name on docs(json_extract(content, '$.name'));


sqlite> explain query plan
   ...> select * from docs 
   ...> where json_extract(content, '$.name') = 'apple';
QUERY PLAN
`--SEARCH TABLE docs USING INDEX docs_name (<expr>=?)

我們對文檔 content 中的 name 節點進行了索引,查詢時可以通過索引提高檢索的速度。

目前還有一個問題,SQLite 并沒有提供原始的 JSON 數據類型,content 字段中仍然可以插入任何數據。這個問題我們可以通過生成列來解決。例如:

sqlite> drop table docs;


sqlite> create table docs(
   ...> content text,
   ...> id int generated always as (json_extract(content, '$.id')) virtual not null
   ...> )
   
sqlite> insert into docs(content) 
   ...> values (json('{"id":1, "name":"apple", "price":6.50}'));

我們將 id 字段定義為一個非空的虛擬生成列,數據來自于 content 字段而不會占用額外的存儲。json_extract() 函數的使用意味著插入無效的 JSON 文檔同樣會返回 Error: malformed JSON 錯誤信息。例如:

sqlite> insert into docs(content) values (json('{"id":1, "name":"apple", "price":6.50]}'));
Error: malformed JSON


sqlite> insert into docs(content) values (json('{"name":"apple", "price":6.50}'));
Error: NOT NULL constraint failed: docs.id

第一個錯誤是因為文檔不是有效的 JSON 格式,第二個錯誤是因為文檔中沒有 id 節點。

由于 SQLite 生成列無法作為主鍵字段,我們不能將 id 字段定義為該表的主鍵。不過,我們可以為 id 字段創建一個唯一索引,加上非空約束后的效果和主鍵一樣。

sqlite> create unique index docs_id on docs(id);


sqlite> insert into docs(content) values (json('{"id":1, "name":"banana", "price":8.00}'));
Error: UNIQUE constraint failed: docs.id

接下來我們詳細介紹一下 JSON1 插件。

JSON1 插件概述

json1 插件是一個可加載的擴展,實現了 15 個應用程序定義的 SQL 函數和 2 個表值函數,可以用于管理 SQLite 中的 JSON 文檔。其中,以下 13 個函數是標量函數:

  • json(json),驗證輸入參數是否符合 JSON 格式并返回結果。
  • json_array(value1,value2,...),創建一個 JSON 數組。
  • json_array_length(json),返回 JSON 數組中的元素個數。
  • json_array_length(json,path),返回指定路徑上的 JSON 數組中的元素個數。
  • json_extract(json,path,...),提取指定路徑上的元素。
  • json_insert(json,path,value,...),在指定路徑上插入元素。
  • json_object(label1,value1,...),創建一個 JSON 對象。
  • json_patch(json1,json2),增加、修改或者刪除 JSON 對象中的元素。
  • json_remove(json,path,...),刪除指定路徑上的元素。
  • json_replace(json,path,value,...),替換指定路徑上的元素。
  • json_set(json,path,value,...),設置指定路徑上的元素。
  • json_type(json),返回最外層元素的 JSON 數據類型。
  • json_type(json,path),返回指定路徑上的元素的 JSON 數據類型。
  • json_valid(json),驗證輸入參數是否符合 JSON 格式。
  • json_quote(value),將 SQL 數據轉換為 JSON 格式。

以下 2 個是聚合函數:

  • json_group_array(value),返回聚合后的 JSON 數組。
  • json_group_object(name,value),返回聚合后的 JSON 對象。

以下 2 個是表值函數:

  • json_each(json) 和 json_each(json,path),將 JSON 元素轉換為 SQL 數據行。
  • json_tree(json) 和 json_tree(json,path),遞歸遍歷 JSON 元素并轉換為 SQL 數據行。

json1 插件目前使用文本存儲 JSON 數據。向下兼容意味著 SQLite 只能存儲 NULL、整數、浮點數、文本以及 BLOB,無法增加第 6 個類型“JSON”。

json1 插件目前不支持 JSON 文檔的二進制編碼(BSON)。經過試驗沒有找到比純文本編碼格式明顯更小或者更快的二進制編碼,目前的實現可以支持 1GB/s 的 JSON 文本解析。所有的 json1 函數參數都不接受 BLOB,如果指定這種參數將會報錯,因為 BLOB 是為了將來增強而保留的二進制 JSON 存儲類型。

json1 擴展名中的數字“1”是故意設計的,設計人員預計將來會基于 json1 的經驗創建新的不兼容的 JSON 擴展。一旦獲得足夠的經驗,某種JSON 擴展可能會被添加到 SQLite 核心代碼中。目前,對 JSON 的支持仍然是通過擴展的形式實現。

通用參數說明

對于第一個參數是 JSON 的函數,該參數可以是一個 JSON 對象、數組、數字、字符串或者 null。SQLite 數字和 NULL 值分別被當作 JSON 數字和 null,SQLite 文本可以被當作  JSON 對象、數組或者字符串。如果 SQLite 本文不符合 JSON 對象、數組或者字符串格式,函數將會返回錯誤, json_valid() 和 json_quote() 函數除外。

為了驗證格式的有效性,JSON 輸入參數中開頭和結尾的空白字符將會被忽略。根據 JSON 規范,內部的空白字符也會被忽略。這些函數完全遵循 RFC-7159 JSON 語法。

對于接受 PATH 參數的函數,PATH 必須滿足一定的格式,否則函數將會返回錯誤。滿足格式的 PATH 必須是一個以“\$”符號開頭,加上零個或多個“.objectlabel”或者“[arrayindex]”組成的文本。

其中,arrayindex 通常是一個非負的整數 N,表示選擇數組的第 N 個元素,從 0 開始計數。arrayindex 也可以使用“#-N”的形式,表示選擇從右邊開始的第 N 個元素。數組最后一個元素是“#-1”,字符“#”相當于數據元素的個數。

對于接受 value 參數(value1,value2 等)的函數,這些參數通常被當作引號引用的字符串常量,并且最終解析為 JSON 字符串數據。不過,如果某個 value 參數直接來自另一個 json1 函數的輸出結果,那么該參數將被當作實際的 JSON,傳入的將會是完整的 JSON 而不是字符串常量。

例如,在下面的 json_object() 函數調用中,value 參數看起來像是一個滿足格式的 JSON 數組。但是,由于它是一個普通的 SQL 文本,因此被解析為一個字符串常量,并且作為一個字符串被添加到結果中:

SELECT json_object('ex','[52,3.14159]');
json_object('ex','[52,3.14159]')|
--------------------------------|
{"ex":"[52,3.14159]"}           |

但是,如果一個外部 json_object() 調用中的 value 參數來自另一個函數的結果,例如 json() 或者 json_array(),將會被解析為實際的 JSON 并且作為 JSON 添加到結果中:

SELECT json_object('ex',json('[52,3.14159]'));
json_object('ex',json('[52,3.14159]'))|
--------------------------------------|
{"ex":[52,3.14159]}                   |




SELECT json_object('ex',json_array(52,3.14159));
json_object('ex',json_array(52,3.14159))|
----------------------------------------|
{"ex":[52,3.14159]}                     |

總之,json 參數總是被解釋為 JSON,無論該參數的值來自何處。但是 value 參數只有當其直接來自另一個 json1 函數時才被解釋為 JSON。

JSON 函數說明

接下來我們詳細介紹 json1 擴展中的各種函數。

json()

json(X) 函數可以驗證參數 X 符合 JSON 字符串的格式,并且返回一個精簡版的 JSON 字符串(刪除了所有不必要的空白字符)。如果 X 不是一個格式正確的 JSON 字符串,函數將會返回錯誤。

如果參數 X 是一個包含重復標簽的 JSON 對象,不確定是否保留重復元素。當前實現保留了重復元素,但是將來可能會刪除重復元素,而且沒有提示。例如:

SELECT json(' { "this" : "is", "a": [ "test" ] } ') AS doc;
doc                       |
--------------------------|
{"this":"is","a":["test"]}|




SELECT json(' { "this" : "is", "a": [ "test" } ') AS doc;
SQL Error [1]: [SQLITE_ERROR] SQL error or missing database (malformed JSON)

json_array()

json_array(value1,value2,...) 函數接收零個或多個參數,并且返回一個由這些參數組成的 JSON 數組。如果任何參數是 BLOB,函數將會返回錯誤。

TEXT 類型的參數通常會轉換為引號包含的 JSON 字符串。但是,如果該參數來自其他 json1 函數的輸出,將會作為 JSON 傳入。這種處理方式可以實現 json_array() 和 json_object() 函數的嵌套調用。json() 函數也可以將字符串轉換為 JSON。

例如:

SELECT json_array(1,2,'3',4) AS doc;
doc        |
-----------|
[1,2,"3",4]|


SELECT json_array('[1,2]') AS doc;
doc      |
---------|
["[1,2]"]|


SELECT json_array(json_array(1,2)) AS doc;
doc    |
-------|
[[1,2]]|


SELECT json_array(1,null,'3','[4,5]','{"six":7.7}') AS doc;
doc                                 |
------------------------------------|
[1,null,"3","[4,5]","{\"six\":7.7}"]|


SELECT json_array(1,null,'3',json('[4,5]'),json('{"six":7.7}')) AS doc;
doc                           |
------------------------------|
[1,null,"3",[4,5],{"six":7.7}]|

json_array_length()

json_array_length(X) 函數返回 JSON 數組 X 中的元素個數,如果 X 是其他 JSON 數據而不是數組時返回 0。json_array_length(X,P) 函數返回路徑 P 對應數組中的元素個數,如果 X 或者路徑 P 對應的是其他 JSON 數據而不是數組時返回 0,如果路徑 P 沒有對應的元素時返回 NULL。如果 X 不是一個格式正確的 JSON 字符串,或者 P 不是一個格式正確的路徑,函數將會返回錯誤。

例如:

SELECT json_array_length('[1,2,3,4]') AS length;
length|
------|
     4|


SELECT json_array_length('[1,2,3,4]', '$') AS length;
length|
------|
     4|


SELECT json_array_length('[1,2,3,4]', '$[2]') AS length;
length|
------|
     0|


SELECT json_array_length('{"one":[1,2,3]}') AS length;
length|
------|
     0|


SELECT json_array_length('{"one":[1,2,3]}', '$.one') AS length;


SELECT json_array_length('{"one":[1,2,3]}', '$.two') AS length;
length|
------|
      |

json_extract()

json_extract(X,P1,P2,...) 函數提取并返回 JSON 數據 X 中的一個或多個元素。如果只提供了路徑 P1,對于 JSON null 返回的數據類型為 NULL,對于 JSON 數字返回的數據類型為 INTEGER 或者 REAL,對于 JSON false 返回的數據為 INTEGER 類型的 0,對于 JSON true 返回的數據為 INTEGER 類型的 1,對于 JSON 字符串返回的數據類型為去掉引號的文本,對于 JSON 對象和數組返回的是它們的文本形式。如果指定了多個路徑參數(P1、P2 等),函數將會返回 SQLite 文本形式的 JSON 數組,包含了每個路徑對應的數據。

例如:

SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$') AS doc;
doc                      |
-------------------------|
{"a":2,"c":[4,5,{"f":7}]}|


SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c') AS doc;
doc          |
-------------|
[4,5,{"f":7}]|


SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2]') AS doc;
doc    |
-------|
{"f":7}|


SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2].f') AS doc;
doc|
---|
  7|


SELECT json_extract('{"a":2,"c":[4,5],"f":7}','$.c','$.a') AS doc;
doc      |
---------|
[[4,5],2]|


SELECT json_extract('{"a":2,"c":[4,5],"f":7}','$.c[#-1]') AS doc;
doc|
---|
  5|


SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x') AS doc;
doc|
---|
   |


SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x', '$.a') AS doc;
doc     |
--------|
[null,2]|

json_insert()、json_replace 和 json_set()

json_insert(json,path,value,...)、json_replace(json,path,value,...) 和 json_set(json,path,value,...) 函數的第一個參數是一個 JSON 數據,加上零個或多個路徑和數據的參數對,使用 path/value 參數對更新輸入的 JSON 數據后返回一個新的 JSON 字符串。這些函數的區別僅僅在于創建新值和覆蓋舊值得方式不同。

函數

是否覆蓋已有元素

是否創建不存在的元素

json_insert()

?

??

json_replace()

??

?

json_set()

??

??

這三個函數參數的個數總是奇數,第一個參數總是需要修改的原始 JSON。隨后的參數成對出現,每對參數中的第一個是路徑,第二個是在該路徑上插入、替換或者設置的數據。

數據的修改按照從左至右的順序執行,前面的數據更改會影響后續的路徑搜索。

如果某個 path/value 參數對中的數據是 TEXT 類型,通常來說將會作為一個引號引用的 JSON 字符串插入,即使這個字符串看起來像有效的 JSON。不過,如果該數據值另一個 json1 函數(例如 json()、json_array() 或者 json_object())的結果,將被解釋為一個 JSON 插入并且保留所有的子結構。

如果第一個參數不是一個格式正確的 JSON,或者任何 PATH 不是一個格式正確的路徑,或者任何參數是 BLOB,函數將會返回錯誤。

如果想要在數據的最后追加元素,可以使用 json_insert() 函數并且指定索引下標“#”。例如:

SELECT json_insert('[1,2,3,4]','$[#]',99) AS doc;
doc         |
------------|
[1,2,3,4,99]|




SELECT json_insert('[1,[2,3],4]','$[1][#]',99) AS doc;
doc           |
--------------|
[1,[2,3,99],4]|

其他示例:

SELECT json_insert('{"a":2,"c":4}', '$.a', 99) AS doc;
doc          |
-------------|
{"a":2,"c":4}|


SELECT json_insert('{"a":2,"c":4}', '$.e', 99) AS doc;
doc                 |
--------------------|
{"a":2,"c":4,"e":99}|


SELECT json_replace('{"a":2,"c":4}', '$.a', 99) AS doc;
doc           |
--------------|
{"a":99,"c":4}|


SELECT json_replace('{"a":2,"c":4}', '$.e', 99) AS doc;
doc          |
-------------|
{"a":2,"c":4}|


SELECT json_set('{"a":2,"c":4}', '$.a', 99) AS doc;
doc           |
--------------|
{"a":99,"c":4}|


SELECT json_set('{"a":2,"c":4}', '$.e', 99) AS doc;
doc                 |
--------------------|
{"a":2,"c":4,"e":99}|


SELECT json_set('{"a":2,"c":4}', '$.c', '[97,96]') AS doc;
doc                  |
---------------------|
{"a":2,"c":"[97,96]"}|


SELECT json_set('{"a":2,"c":4}', '$.c', json('[97,96]')) AS doc;
doc                |
-------------------|
{"a":2,"c":[97,96]}|


SELECT json_set('{"a":2,"c":4}', '$.c', json_array(97,96)) AS doc;
doc                |
-------------------|
{"a":2,"c":[97,96]}|

json_object()

json_object(label1,value1,...) 函數接收零個或多個參數對,并且返回一個由這些參數組成的 JSON 對象。。每對參數中的第一個是元素標簽,第二個是對應的數據。如果任何參數是 BLOB,函數將會返回錯誤。

json_object() 函數目前可以接受重復的元素標簽,將來可能不允許。

如果只傳入一個 TEXT 類型的參數,即使它是一個格式正確的 JSON,通常也會被轉換為引號引用的 JSON 字符串。不過,如果該參數直接來自其他 json1 函數的輸出,將被被當作 JSON 處理,所有的類型信息和子結構都會保留。這種處理方式可以實現 json_array() 和 json_object() 函數的嵌套調用。json() 函數也可以將字符串轉換為 JSON。

例如:

SELECT json_object('a',2,'c',4) AS doc;
doc          |
-------------|
{"a":2,"c":4}|


SELECT json_object('a',2,'c','{e:5}') AS doc;
doc                |
-------------------|
{"a":2,"c":"{e:5}"}|


SELECT json_object('a',2,'c',json_object('e',5)) AS doc;
doc                |
-------------------|
{"a":2,"c":{"e":5}}|

json_patch()

json_patch(T,P) 函數利用 RFC-7396 MergePatch 算法將補丁 P 應用到輸入 T,返回修補之后的 T 副本。

MergePatch 可以增加、修改或者刪除 JSON 對象中的元素,因此對于 JSON 對象,json_patch() 函數一般可以作為 json_set() 和 json_remove() 函數的替代。不過,MergePatch 將 JSON 數組當作原子對象處理,不能追加或者修改數組中的單個元素,只能將整個數組作為一個單元進行插入、替換或者刪除。因此,json_patch() 對于處理包含數組(尤其是數組中包含很多子結構)的 JSON 用處不大。

例如:

SELECT json_patch('{"a":1,"b":2}','{"c":3,"d":4}') AS doc;
doc                      |
-------------------------|
{"a":1,"b":2,"c":3,"d":4}|


SELECT json_patch('{"a":[1,2],"b":2}','{"a":9}') AS doc;
doc          |
-------------|
{"a":9,"b":2}|


SELECT json_patch('{"a":[1,2],"b":2}','{"a":null}') AS doc;
doc    |
-------|
{"b":2}|


SELECT json_patch('{"a":1,"b":2}','{"a":9,"b":null,"c":8}') AS doc;
doc          |
-------------|
{"a":9,"c":8}|


SELECT json_patch('{"a":{"x":1,"y":2},"b":3}','{"a":{"y":9},"c":8}') AS doc;
doc                            |
-------------------------------|
{"a":{"x":1,"y":9},"b":3,"c":8}|

json_remove()

json_remove(X,P,...) 函數第一個參數 X 是一個 JSON 數據,加上零個或多個路徑參數 P,返回一個刪除指定元素后的 JSON。如果指定路徑上沒有對應的元素,忽略該參數。

數據的刪除按照從左至右的順序執行,前面的數據更改會影響后續的路徑搜索。

如果沒有指定路徑參數,json_remove(X) 函數將會返回格式化后的 X,刪除了多余的空白字符。

如果第一個參數不是一個格式正確的 JSON,或者任何 PATH 不是一個格式正確的路徑,或者任何參數是 BLOB,函數將會返回錯誤。

例如:

SELECT json_remove('[0,1,2,3,4]','$[2]') AS doc;
doc      |
---------|
[0,1,3,4]|


SELECT json_remove('[0,1,2,3,4]','$[2]','$[0]') AS doc;
doc    |
-------|
[1,3,4]|


SELECT json_remove('[0,1,2,3,4]','$[0]','$[2]') AS doc;
doc    |
-------|
[1,2,4]|


SELECT json_remove('[0,1,2,3,4]','$[#-1]','$[0]') AS doc;
doc    |
-------|
[1,2,3]|


SELECT json_remove('{"x":25,"y":42}') AS doc;
doc            |
---------------|
{"x":25,"y":42}|


SELECT json_remove('{"x":25,"y":42}','$.z') AS doc;
doc            |
---------------|
{"x":25,"y":42}|


SELECT json_remove('{"x":25,"y":42}','$.y') AS doc;
doc     |
--------|
{"x":25}|


SELECT json_remove('{"x":25,"y":42}','$') AS doc;
doc|
---|
   |

json_type()

json_type(X) 函數返回 X 最外層元素的 JSON 數據類型。json_type(X,P) 函數返回路徑 P 對應元素的 JSON 數據類型。json_type() 函數返回的結果為以下字符串之一:'null'、'true'、'false'、'integer'、'real'、'text'、'array' 或者 'object'。如果 json_type(X,P) 函數中的路徑 P 對應的元素不存在,函數將會返回 NULL。

如果參數不是一個格式正確的 JSON,或者參數是 BLOB,函數將會返回錯誤。

例如:

SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}') AS type;
type  |
------|
object|


SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$') AS type;
type  |
------|
object|


SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a') AS type;
type |
-----|
array|


SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[0]') AS type;
type   |
-------|
integer|


SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[1]') AS type;
type|
----|
real|


SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[2]') AS type;
type|
----|
true|


SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[3]') AS type;
type |
-----|
false|


SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[4]') AS type;
type|
----|
null|


SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[5]') AS type;
type|
----|
text|


SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[6]') AS type;
type|
----|
    |

json_valid()

json_valid(X) 函數用于驗證參數的格式。如果 X 是一個格式正確的 JSON,函數返回 1;否則,函數返回 0。

例如:

SELECT json_valid('{"x":35}') AS is_json;
is_json|
-------|
      1|


SELECT json_valid('{"x":35') AS is_json;
is_json|
-------|
      0|

json_quote()

json_quote(X) 函數將 SQL 數據 X(一個數字或者字符串)轉換為對應的 JSON 形式。例如:

SELECT json_quote(3.14159) AS json;
json   |
-------|
3.14159|


SELECT json_quote('verdant') AS json;
json     |
---------|
"verdant"|

json_group_array() 和 json_group_object()

json_group_array(X) 函數是一個聚合函數,返回一個由所有 X 構成的 JSON 數組。例如:

SELECT json_group_array(X)
FROM (
  SELECT json_array(1,2) AS X
  UNION ALL
  SELECT json_array(3,4)
  UNION ALL
  SELECT 5
) t;
json_group_array(X)|
-------------------|
[[1,2],[3,4],5]    |

與此類似,json_group_object(NAME,VALUE) 也是一個聚合函數,返回一個由所有 NAME/VALUE 對組成的 JSON 對象。例如:

SELECT json_group_object(name, value)
FROM (
  SELECT 'first' AS name, json_object('a',2,'c',4) AS value
  UNION ALL
  SELECT 'rgb', json_array(255,255,255)
  UNION ALL 
  SELECT 'id', 100
) t;
json_group_object(name, value)                      |
----------------------------------------------------|
{"first":{"a":2,"c":4},"rgb":[255,255,255],"id":100}|

json_each() 和 json_tree()

json_each(X) 和 json_tree(X) 表值函數將輸入參數 X 中的每個元素轉換為一行數據。json_each(X) 函數只遍歷頂層 JSON 數組或者對象的直接子節點,如果頂層元素是一個基本值則只返回該節點自身。json_tree(X) 函數從頂層元素開始遞歸遍歷所有的 JSON 子結構。

json_each(X,P) 和 json_tree(X,P) 函數和上面兩個函數類似,只是它們將路徑 P 對應的元素作為頂層元素。

json_each() 和 json_tree() 函數返回的表結構如下:

CREATE TABLE json_tree(
    key ANY,             -- key for current element relative to its parent
    value ANY,           -- value for the current element
    type TEXT,           -- 'object','array','string','integer', etc.
    atom ANY,            -- value for primitive types, null for array & object
    id INTEGER,          -- integer ID for this element
    parent INTEGER,      -- integer ID for the parent of this element
    fullkey TEXT,        -- full path describing the current element
    path TEXT,           -- path to the container of the current row
    json JSON HIDDEN,    -- 1st input parameter: the raw JSON
    root TEXT HIDDEN     -- 2nd input parameter: the PATH at which to start
);
  • 字段 key 是 JSON 數組中每個元素的下標,或者 JSON 對象中每個元素的標簽。其他情況下,key 字段為空。
  • 字段 atom 是基本元素(除了 JSON 數組和對象之外的元素)對應的 SQL 值,JSON 數組和對象的 atom 字段為空。對于基本 JSON 元素而言,字段 value 的值和 atom 字段相同;對于 JSON 數組和對象元素而言,字段 value 是文本格式的 JSON 數據。
  • 字段 type 的值是一個 SQL 文本,根據 JSON 元素的類型不同可能的取值為 'null'、'true'、'false'、'integer'、'real'、'text'、'array' 或者 'object'。
  • 字段 id 是一個整數,標識了 JSON 字符串中的每個的 JSON 元素。id 是一個內部生成的編號,計算方法在將來的版本中可能會發生改變。唯一可以確認的是每一行都會有一個不同的編號。
  • 字段 parent 對于 json_each() 函數總是返回 NULL。對于 json_tree() 函數,字段 parent 是當前元素的父節點 id;如果是頂層元素,字段的值為 NULL。
  • 字段 fullkey 是一個文本值,標識了當前元素在原始 JSON 字符串中的路徑。即使通過參數 root 提供了其他的起點,也會返回從真正的頂層元素開始的完整路徑。
  • 字段 path 是到包含當前行的數組或對象容器的路徑,或者頂層元素是一個基本類型時(意味著函數只返回當前行)到當前行的路徑。

假設存在以下 user 表:

CREATE TABLE user(name, phone);
INSERT INTO user(name, phone) VALUES ('anne', json_array('010-12345678', '020-10003333'));
INSERT INTO user(name, phone) VALUES ('tony', json_array('010-12349999', '800-10007777'));

字段 phone 中使用 JSON 數組的形式存儲了零個或多個電話號碼。以下語句可以找出電話號碼以 020 開頭的用戶:

SELECT DISTINCT user.name
  FROM user, json_each(user.phone)
 WHERE json_each.value LIKE '010-%';
name|
----|
anne|

現在假設當用戶只有一個電話號碼時,字段 phone 中存儲的是普通文本。例如:

INSERT INTO user(name, phone) VALUES ('kevin', '020-10005555');

現在同樣需要找出電話號碼以 020 開頭的用戶。由于 json_each() 函數要求第一個參數是一個格式正確的 JSON,因此它只能用于包含 2 個或更多電話號碼的用戶:

SELECT name FROM user WHERE phone LIKE '020-%'
UNION ALL
SELECT user.name
  FROM user, json_each(user.phone)
 WHERE json_valid(user.phone)
   AND json_each.value LIKE '020-%';
name |
-----|
 anne|
kevin|

假設存在以下 big 表:

CREATE TABLE big(json JSON);
INSERT INTO big(json) VALUES (json_object('name', 'anne','phone', json_array('010-12345678', '020-10003333')));
INSERT INTO big(json) VALUES (json_object('name', 'tony','phone', json_array('010-12349999', '800-10007777')));

如果想要逐行返回數據中的內容,可以執行以下語句:

SELECT big.rowid, fullkey, value
  FROM big, json_tree(big.json)
 WHERE json_tree.type NOT IN ('object','array');
rowid|fullkey   |value       |
-----|----------|------------|
    1|$.name    |anne        |
    1|$.phone[0]|010-12345678|
    1|$.phone[1]|020-10003333|
    2|$.name    |tony        |
    2|$.phone[0]|010-12349999|
    2|$.phone[1]|800-10007777|

查詢條件中的 type NOT IN ('object','array') 從結果中去除了容器節點,只返回了葉子元素。我們也可以使用以下語句實現相同的效果:

SELECT big.rowid, fullkey, atom
  FROM big, json_tree(big.json)
 WHERE atom IS NOT NULL;

假設 big.json 字段中的每一行是一個 JSON 對象,包含一個唯一標識節點'\$.id' 和一個嵌套其他對象的 '\$.partlist' 節點。例如:

INSERT INTO big(json) VALUES (json_object('id', 1,'partlist', json_array('6fa5181e-5721-11e5-a04e-57f3d7b32808', 'a18437b3-b6c4-4473-a9c5-50e7b8eef6be')));
INSERT INTO big(json) VALUES (json_object('id', 2,'partlist', json_object('uuid','6fa5181e-5721-11e5-a04e-57f3d7b32808')));
INSERT INTO big(json) VALUES (json_object('id', 3,'partlist', json_array(json_object('uuid','e7e3845d-cdfe-48aa-877f-9121b970761d'),json_object('uuid','6fa5181e-5721-11e5-a04e-57f3d7b32808'))));

如果想要找出 '$.partlist' 元素中任意節點包含一個或多個 uuid 為 '6fa5181e-5721-11e5-a04e-57f3d7b32808' 的文檔,可以使用以下語句:

SELECT DISTINCT json_extract(big.json,'$.id')
  FROM big, json_tree(big.json, '$.partlist')
 WHERE json_tree.key='uuid'
   AND json_tree.value='6fa5181e-5721-11e5-a04e-57f3d7b32808';
json_extract(big.json,'$.id')|
-----------------------------|
                            2|
                            3|

編譯 JSON1 插件

SQLite 可加載擴展文檔描述了如何將可加載擴展編譯為共享庫。文檔中描述的方法也適用于 json1 模塊。

json1 源代碼包含在 SQLite 程序包中,默認沒有啟用編譯。可以使用 -DSQLITE_ENABLE_JSON1 編譯時選項啟用 json1 擴展。編譯命令行工具和測試工具時,標準的 makefile 中包含了該選項,所以命令行工具可以使用 json1。

版本支持

json1 擴展使用了 SQLite 3.9.0 引入的 sqlite3_value_subtype() 和sqlite3_result_subtype() 接口,因此更早版本的 SQLite 無法使用 json1 擴展。

當前的 JSON 庫實現使用了一個遞歸下降語法解析器。為了避免使用過多的堆棧空間,任何超過 2000 層嵌套的 JSON 輸入都被視為無效數據。嵌套級別的限制符合 RFC-7159 section 9 規定的 JSON 兼容實現。

總結

本文介紹了 SQLite 中的文檔存儲功能。我們可以借助于 json1 擴展插件提供的 JSON 函數實現文檔數據的存儲以及 JSON 文檔和 SQL 數據的相互轉換,同時還可以利用 SQLite 表達式索引和生成列為 JSON 數據提供索引支持,從而實現了將 SQLite 作為一個文檔數據庫使用。

責任編輯:華軒 來源: SQL編程思想
相關推薦

2021-09-12 17:25:12

SQLite數據庫

2011-07-20 12:34:49

SQLite數據庫約束

2019-08-15 07:00:54

SQLite數據庫內存數據庫

2017-07-12 09:20:42

SQLite數據庫移植

2011-08-04 18:00:47

SQLite數據庫批量數據

2011-08-02 16:16:08

iPhone開發 SQLite 數據庫

2011-08-24 13:49:45

Access數據庫轉化

2011-07-05 10:16:16

Qt 數據庫 SQLite

2018-07-13 09:20:30

SQLite數據庫存儲

2011-04-18 13:40:15

SQLite

2017-05-03 13:50:38

2011-07-01 14:06:57

Qt sqlite

2013-04-10 14:21:35

2023-10-17 08:31:03

SQLite數據庫

2011-08-30 14:15:34

QTSQLite數據庫

2010-03-04 15:31:44

Python SQLI

2023-11-24 11:11:08

Python數據庫

2011-07-05 14:46:34

2009-12-07 17:33:44

PHP SQlite數

2010-01-27 18:33:16

Android SQL
點贊
收藏

51CTO技術棧公眾號

亚洲精品美女在线观看| ...av二区三区久久精品| 4438全国成人免费| 免费网站在线高清观看| 日韩激情精品| 岛国av午夜精品| 亚洲在线观看一区| 懂色av一区二区三区四区| 亚洲欧美大片| 美女视频黄免费的亚洲男人天堂| 成人午夜精品无码区| 朝桐光一区二区| 亚洲综合一区二区精品导航| 欧美日韩大片一区二区三区| aaaa一级片| 日韩成人一级片| 国外成人在线直播| 小泽玛利亚一区二区免费| 亚洲高清极品| 精品国内片67194| 激情视频免费网站| 性国裸体高清亚洲| 一区二区三区在线观看网站| 欧美人xxxxx| 国产小视频一区| 日韩av成人高清| 97人人模人人爽人人喊中文字| 国产福利视频网站| 成人嘿咻视频免费看| 亚洲精品久久久久| 色哟哟无码精品一区二区三区| 欧美综合影院| 欧美亚洲自拍偷拍| 免费在线观看的av网站| 超碰激情在线| 亚洲一区二区高清| 国产一二三四区在线观看| 97超碰国产一区二区三区| 91麻豆国产自产在线观看| 99久久自偷自偷国产精品不卡| 最近中文字幕免费观看| 久久一区视频| 国产999视频| 一本一道无码中文字幕精品热| 亚洲国产电影| 久久久亚洲网站| 国产一级免费av| 国产精品扒开腿做爽爽爽软件| 日韩一区二区欧美| 在线观看日本黄色| 日韩欧美中字| 日日狠狠久久偷偷四色综合免费 | 偷拍自拍亚洲色图| 日韩av综合中文字幕| 少妇激情一区二区三区视频| 国产图片一区| 日韩精品福利网站| a毛片毛片av永久免费| 亚洲人亚洲人色久| 亚洲三级免费看| 女人黄色一级片| 久久香蕉国产| 欧美成人午夜激情在线| 美女毛片在线观看| 尹人成人综合网| 97成人精品区在线播放| 黑人精品无码一区二区三区AV| 国产亚洲激情| 国产成人一区二区在线| 在线观看亚洲国产| 国产在线看一区| 99中文视频在线| 色哟哟国产精品色哟哟| 久久久五月婷婷| 日韩中文字幕一区二区| 欧美被日视频| 亚洲一区二区三区精品在线| 两根大肉大捧一进一出好爽视频| 亚洲成人看片| 欧美高清视频不卡网| 亚洲少妇一区二区| 日韩在线你懂的| 精品国产一区二区三区四区在线观看 | 不卡影院免费观看| 日本一区二区在线视频观看| 欧美成年黄网站色视频| 亚洲国产aⅴ成人精品无吗| 国产午夜福利在线播放| 自拍偷拍一区二区三区四区| 亚洲爱爱视频| 日韩一区二区免费电影| 插我舔内射18免费视频| 狠狠做六月爱婷婷综合aⅴ | 国产三级在线免费| √…a在线天堂一区| 日韩av高清在线看片| 日韩精品免费观看视频| 欧美videos中文字幕| 性欧美丰满熟妇xxxx性仙踪林| 日韩一区电影| 97视频com| 国产精品午夜福利| 久久亚洲一区二区三区明星换脸 | www.自拍偷拍| 亚洲综合婷婷| 国产激情久久久| 精品人妻一区二区三区三区四区 | 精品国精品国产尤物美女| 欧美熟妇一区二区| 欧美天天视频| 国产日韩精品视频| 三级在线观看| 亚洲精品福利视频网站| 久久精品视频91| 韩国女主播一区二区三区| 久久精品国产91精品亚洲| 国产a∨精品一区二区三区仙踪林| 日韩精品一级二级 | 欧美网站在线| 国产一区二区色| 国产三级在线免费| 欧美日韩在线观看视频| 午夜影院福利社| 99久久久久| 国产精品黄页免费高清在线观看| 欧美特黄一级视频| 亚洲欧美国产77777| 日本人视频jizz页码69| 国产一区毛片| 日本人成精品视频在线| 天天操天天插天天射| 亚洲综合一区二区| 四虎国产精品永久免费观看视频| 9999国产精品| 国产欧美日韩高清| 大地资源中文在线观看免费版| 欧美日韩国产精品| 中文字幕免费高清视频| 亚洲二区在线| 国产三级精品在线不卡| ririsao久久精品一区| 日韩精品一区二区三区中文不卡| 色老板免费视频| 久久国产精品露脸对白| 亚洲欧洲久久| 88xx成人网| 在线观看久久av| 中文字幕码精品视频网站| 久久精品视频免费| 成人在线观看黄| 国产调教一区二区三区| 国产成+人+综合+亚洲欧洲 | 久久艳片www.17c.com| 一级黄色录像大片| 亚洲三级电影全部在线观看高清| 日韩在线一区视频| 亚洲理论电影网| 99se婷婷在线视频观看| h片在线观看| 精品亚洲国产视频| 国产美女www| 亚洲欧洲色图综合| 国产精品欧美性爱| 亚洲激情网站| 日本在线成人一区二区| 成人在线观看免费播放| 久久九九有精品国产23| xxxx国产精品| 欧美日韩日本国产| 久久精品三级视频| 国产一区二区三区综合| 99久久国产综合精品五月天喷水| 日本久久成人网| 国产精品极品美女粉嫩高清在线| 色网站免费在线观看| 欧美一区二区二区| 日韩 欧美 精品| 国产区在线观看成人精品| 性生生活大片免费看视频| 狠狠色狠狠色综合日日tαg| 久久免费视频1| 另类一区二区三区| 欧美精品国产精品日韩精品| 青青青草原在线| 欧美精品久久久久久久久老牛影院| 欧美日韩免费做爰视频| 99精品国产热久久91蜜凸| 狠狠躁狠狠躁视频专区| 黄色一区二区三区四区| 少妇免费毛片久久久久久久久 | 精品国产乱码久久久久| 日韩av首页| 欧美黄色片视频| 川上优的av在线一区二区| 精品国产不卡一区二区三区| 黄色一级视频免费看| 亚洲欧美日韩人成在线播放| 丰满大乳奶做爰ⅹxx视频| 久久精品99国产精品| 久久99中文字幕| 羞羞色午夜精品一区二区三区| 国产一区免费视频| 99视频这里有精品| 日韩免费观看网站| 欧美人动性xxxxz0oz| 中文字幕日韩欧美在线| 欧美特级特黄aaaaaa在线看| 5566中文字幕一区二区电影| 日韩xxxxxxxxx| 亚洲伦理在线精品| 九九九视频在线观看| 91啪九色porn原创视频在线观看| 日本一二三四区视频| 日韩精品午夜视频| 欧美亚洲日本一区二区三区| 五月天激情综合网| 婷婷亚洲婷婷综合色香五月| 国产区精品视频在线观看豆花| 91久久嫩草影院一区二区| 激情亚洲影院在线观看| 国内精品视频久久| 天使と恶魔の榨精在线播放| 日韩有码在线观看| 黄色av免费在线看| 国产午夜精品理论片a级探花| www.97av.com| 欧美一区在线视频| 亚洲在线视频播放| 欧美视频一区二区三区在线观看| 国产成人精品片| 亚洲不卡一区二区三区| 久草免费在线观看视频| 自拍av一区二区三区| 日韩欧美视频免费观看| 欧美国产在线观看| 香蕉视频久久久| 久久久99久久精品欧美| www.久久国产| 久久影院电视剧免费观看| 亚洲蜜桃精久久久久久久久久久久| 高清shemale亚洲人妖| 91香蕉视频免费看| 黄色资源网久久资源365| 亚洲一级免费在线观看| 蓝色福利精品导航| 中文字幕一区久久| 国模少妇一区二区三区| 国产在线视频三区| 国产福利精品导航| 不许穿内裤随时挨c调教h苏绵| 国产高清精品久久久久| 一级全黄裸体片| 99精品国产99久久久久久白柏| 3d动漫精品啪啪一区二区下载 | 欧美日韩高清在线一区| 亚洲第一二三区| 午夜视频久久久| 婷婷亚洲五月| 国产一级不卡视频| 亚洲成人资源| 欧美成人精品欧美一级乱| 天堂av在线一区| 中文字幕亚洲欧洲| 国产乱码精品一区二区三| 久久久久亚洲av成人网人人软件| 国产91在线观看丝袜| 自拍视频一区二区| 久久精品人人做| 卡通动漫亚洲综合| 亚洲电影在线播放| 一级片视频在线观看| 欧美日韩中文精品| 国产99对白在线播放| 亚洲精品av在线| 福利在线播放| 久久国产精品影片| 美女露胸视频在线观看| 国产精品xxx视频| 91成人app| 国产在线播放一区二区| 精品久久91| 欧美日韩午夜爽爽| 亚洲欧美日韩一区在线观看| 高清一区二区视频| 粉嫩高潮美女一区二区三区| 亚洲国产精品成人综合久久久| 国产精品免费视频网站| 国产真人真事毛片| 欧美在线看片a免费观看| 国产日韩一级片| 日韩电影中文字幕| 黄色在线观看网站| 777国产偷窥盗摄精品视频| 精品亚洲a∨| 精品欧美国产一区二区三区不卡| 日韩精品一卡| 91丨porny丨探花| 另类小说一区二区三区| 屁屁影院国产第一页| 国产精品三级视频| 伊人手机在线视频| 日韩欧美中文一区二区| 久久久久久久久亚洲精品| 久久99视频免费| 欧美日韩在线精品一区二区三区激情综合 | 欧美在线 | 亚洲| 最新69国产成人精品视频免费| bl在线肉h视频大尺度| 国产欧美一区二区| 欧美日韩爱爱| 国产高清av在线播放| 韩国v欧美v日本v亚洲v| 欧美激情亚洲色图| 岛国av一区二区在线在线观看| 国产高清在线观看视频| 中文字幕久热精品视频在线| 在线观看涩涩| 国产日韩亚洲精品| 韩国欧美一区| 奇米777在线| 一区二区中文视频| 中文字幕777| 亚洲色在线视频| 蜜桃视频动漫在线播放| 97视频热人人精品| 婷婷久久综合| 老司机午夜性大片| 欧美极品少妇xxxxⅹ高跟鞋| 欧美日韩一二三四区| 亚洲第一福利在线观看| 色呦呦网站在线观看| 91精品久久久久久久久久另类| 狠狠做深爱婷婷综合一区| 无码人妻h动漫| 99国产精品国产精品毛片| 精品少妇一二三区| 欧美成人vr18sexvr| 在线三级电影| 亚洲在线视频福利| 一区二区三区在线观看免费| 国产欧美一区二| 中文字幕亚洲综合久久菠萝蜜| 亚洲一级片免费看| 色多多国产成人永久免费网站 | 久久久无码中文字幕久...| 久久精品国产免费| 97精品在线播放| 欧美高清视频一二三区 | 日本激情在线观看| 国产精品专区一| 99re6这里只有精品| 亚洲怡红院在线| 亚洲精品一二三| 欧美一级片免费| 5566日本婷婷色中文字幕97| 亚洲日本三级| www.99av.com| 一区二区中文视频| 成人福利小视频| 97在线视频免费播放| 免费成人结看片| www.久久久精品| 亚洲黄色免费电影| 姝姝窝人体www聚色窝| 欧洲日韩成人av| 欧美自拍偷拍| 精品人妻一区二区三区免费| 亚洲综合区在线| 手机福利小视频在线播放| 国产精品96久久久久久又黄又硬| 日韩欧美三级| 国产精品偷伦视频免费观看了| 午夜视频在线观看一区| 男男激情在线| 91手机视频在线观看| 韩日欧美一区| 免费观看av网站| 欧美精品国产精品| 男女免费观看在线爽爽爽视频| 久久久久国产精品视频| 麻豆一区二区三区| 国产无遮挡aaa片爽爽| 国产视频精品在线| **日韩最新| 国产美女三级视频| 日韩毛片在线免费观看| 无码国产精品96久久久久| 国产精品一区二区在线| 激情综合中文娱乐网| 欧美福利第一页| 亚洲国产成人爱av在线播放| 亚洲第一会所001| 成人污网站在线观看| 久久久青草青青国产亚洲免观| 国产精品视频第一页| 欧美一级淫片aaaaaaa视频| 仙踪林久久久久久久999| 加勒比精品视频| 欧美一区二区高清| 国产私拍福利精品视频二区|