精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

亚洲精品乱码久久久久久动漫| 免费国产一区| 精品在线视频观看| 免费成人网www| 欧美人与z0zoxxxx视频| 日本大片免费看| 男人的天堂在线| 国产在线精品一区二区夜色| 欧美激情视频在线| 日本激情小视频| 精品午夜av| 日本福利一区二区| 99久久久精品视频| 在线观看国产原创自拍视频| 粉嫩av亚洲一区二区图片| 欧美与黑人午夜性猛交久久久| 精品人妻伦九区久久aaa片| 欧美wwwsss9999| 91精品国产综合久久婷婷香蕉 | 岛国精品一区二区三区| 性欧美1819sex性高清| 亚洲人123区| 深夜福利成人| 日本一区二区三区在线观看视频| 国产精品一区二区久激情瑜伽| 国产精品高潮呻吟久久av无限| 国产精品a成v人在线播放| 97偷自拍亚洲综合二区| 亚洲欧美一区二区精品久久久| 91丨porny丨九色| 欧美aaaaaaaa| 91国偷自产一区二区开放时间 | 狠狠色丁香久久婷婷综合_中| 97精品在线视频| 欧美精品入口蜜桃| 91九色精品国产一区二区| 亚洲欧美日韩精品久久亚洲区 | www欧美激情| 最新中文字幕在线播放| 亚洲二区在线视频| 亚洲一区 在线播放| 91大神在线网站| 国产清纯在线一区二区www| 久久国产主播精品| 四虎永久在线精品免费网址| 国产成人自拍网| 91亚洲精品在线观看| 91亚洲国产成人久久精品麻豆| 日韩不卡在线观看日韩不卡视频| 国产成人精品久久二区二区91| 人人干人人干人人干| 亚洲国产99| 久久久久久久爱| 久久无码精品丰满人妻| 影音先锋中文字幕一区二区| 久久久亚洲成人| 国产一区二区免费| 国产精品久久国产| 男女免费观看在线爽爽爽视频| 亚洲品质自拍视频网站| 日韩最新中文字幕| 性欧美video高清bbw| 亚洲精品成a人| 日韩成人三级视频| www在线观看黄色| 日韩欧美国产高清91| 国产三区在线视频| 亚洲综合在线电影| 欧美理论电影在线| 亚洲av毛片在线观看| 日韩成人在线看| 亚洲国产美女久久久久| 西西大胆午夜视频| 国产日产一区| 久久久国产在线视频| 黑鬼狂亚洲人videos| 欧美精品一区二区三区久久久竹菊| 久久久久久久久网站| 久久久久久久久久免费视频| 老鸭窝91久久精品色噜噜导演| 国产精品扒开腿爽爽爽视频| 国产老妇伦国产熟女老妇视频| 国产99久久久国产精品免费看| 国产一区二区视频在线免费观看| 韩国中文字幕2020精品| 亚洲同性gay激情无套| r级无码视频在线观看| 在线播放第一页| 98色花堂精品视频在线观看| 色综合网站在线| 日本77777| 卡通动漫国产精品| 日韩在线观看网址| 日韩av电影网| 久久国产精品99久久人人澡| 国产伦精品一区二区三区高清版| 黄色片在线免费看| 亚洲精品欧美综合四区| 337p粉嫩大胆噜噜噜鲁| 香蕉久久久久久| 日韩av网站电影| 免费黄色国产视频| 一本色道精品久久一区二区三区| 国产免费成人av| 午夜影院在线视频| 亚洲激情成人在线| 国产免费视频传媒| 精品视频自拍| 久久国产精品亚洲| 亚洲 国产 日韩 欧美| 成人综合婷婷国产精品久久免费| 日韩精品伦理第一区| 啪啪免费视频一区| 欧美视频一区二区三区在线观看 | www.亚洲在线| 在线综合视频网站| 三上悠亚一区二区| 亚洲国产三级网| 91麻豆免费视频网站| 日韩av一级片| 美女主播视频一区| 丁香花电影在线观看完整版| 在线播放国产精品二区一二区四区 | 国产成人精品av久久| 久久99久久99精品免视看婷婷| 欧美日韩日本网| 超碰在线cao| 精品女同一区二区| 青青草手机视频在线观看| 麻豆91小视频| 亚洲精品一区二区三区四区五区| 欧美电影免费看| 日韩电影第一页| 久久在线视频精品| 福利一区福利二区| 成人国产在线看| 亚洲欧美在线人成swag| 中文字幕亚洲国产| 中文字幕一二区| 日本一区二区三区在线观看| 日本新janpanese乱熟| 免费久久久久久久久| 97avcom| 无码精品一区二区三区在线| 亚洲国产精品久久久男人的天堂| 美女被艹视频网站| 欧美黄色免费| 91黄色国产视频| 调教一区二区| 精品欧美久久久| 国产无码精品久久久| 成人看片黄a免费看在线| 黄色大片中文字幕| 秋霞影视一区二区三区| 日产精品久久久一区二区福利| 飘雪影院手机免费高清版在线观看| 欧美日韩综合视频网址| 好吊视频在线观看| 免费在线观看日韩欧美| 成年人黄色在线观看| 精品国产亚洲日本| 欧美激情在线视频二区| 无码精品视频一区二区三区| 色婷婷国产精品综合在线观看| 亚洲v国产v欧美v久久久久久| 视频一区二区三区中文字幕| 婷婷五月色综合| 国产欧美88| 性色av一区二区三区红粉影视| 天堂中文资源在线观看| 色综合久久久久网| 天堂网av2018| 丁香网亚洲国际| 欧美精品一区免费| 91日韩在线| av资源站久久亚洲| 久久人体大尺度| 久久精品国产清自在天天线| 丰满少妇高潮在线观看| 日本高清免费不卡视频| 久久久久久视频| av在线不卡网| 男女污污的视频| 午夜精品视频| 日本黄网免费一区二区精品| 久久久久亚洲精品中文字幕| 97香蕉超级碰碰久久免费软件| 国产二区在线播放| 精品国产欧美一区二区| 色偷偷88888欧美精品久久久| 2023国产精品| 国产成人一区二区三区| 理论片午午伦夜理片在线播放| 日韩一区二区视频在线观看| www.中文字幕在线观看| 国产日韩欧美高清| 国产人妻精品午夜福利免费| 丝袜美腿亚洲一区| 伊人久久在线观看| 国产欧美亚洲精品a| 97在线电影| 亚洲不卡系列| 久久久久九九九九| 午夜免费视频在线国产| 亚洲国产精品999| 91极品身材尤物theporn| 欧美日韩国产一区在线| www深夜成人a√在线| 国产日韩三级在线| 国模无码视频一区| 国内精品久久久久影院色| 2022亚洲天堂| 影音先锋久久精品| ijzzijzzij亚洲大全| 青草国产精品| 欧美日本亚洲| 久久久久97| 97netav| 伊人久久一区| 国产精品日韩久久久久| 午夜不卡影院| 97视频免费在线看| 人交獸av完整版在线观看| 久久精品99久久久久久久久| 黄色av网站在线看| 亚洲欧美制服综合另类| 午夜性色福利影院| 精品国产亚洲在线| а√天堂资源在线| 91精品福利在线一区二区三区 | 男人天堂资源网| 国产亚洲欧美在线| 一本色道久久综合亚洲精品图片| 丁香亚洲综合激情啪啪综合| 肉丝美足丝袜一区二区三区四| 久88久久88久久久| 小泽玛利亚视频在线观看| 视频一区国产视频| 一区二区在线播放视频| 日韩电影免费在线看| 欧美性猛交xxx乱久交| 日本亚洲欧美天堂免费| 日日摸天天爽天天爽视频| 久久精品九九| 男人女人黄一级| 免费人成在线不卡| 国产无遮挡猛进猛出免费软件| 日本亚洲最大的色成网站www| 99视频免费播放| 日本aⅴ亚洲精品中文乱码| 中文字幕国产免费| 久久99国产精品久久99果冻传媒| 男人午夜视频在线观看| 国产精品小仙女| 亚洲成年人在线观看| www.亚洲人| 亚洲欧洲久久久| 中文字幕免费观看一区| 久久一级免费视频| 亚洲精品国产一区二区精华液| 国产在线拍揄自揄拍无码视频| 亚洲va欧美va人人爽午夜| 亚洲午夜18毛片在线看| 日本韩国欧美一区| 国产精品亚洲欧美在线播放| 欧美一个色资源| 亚洲av电影一区| 在线看欧美日韩| 操你啦视频在线| 久久久久久久久久久亚洲| 一区二区三区短视频| 国产精品一区二区性色av| 国产精选久久| 精品国产综合久久| 日韩免费一区| 欧美一区二区视频在线播放| 男人的天堂成人在线| 天天干天天草天天| 丁香婷婷深情五月亚洲| 国精产品一区一区三区免费视频| 欧美国产国产综合| 免费网站看av| 色综合久久久久久久久久久| 一级日韩一级欧美| 亚洲国产黄色片| 男人的天堂在线视频免费观看| 欧美精品成人在线| av激情成人网| 国产伦精品一区二区三毛| 欧美理论在线播放| 天堂8在线天堂资源bt| 三级欧美韩日大片在线看| 精品人妻一区二区三区免费| 高潮久久久久久久久久久久久久 | 一区两区小视频| 日韩欧美中文一区| 极品白浆推特女神在线观看| 欧美精品手机在线| 日本国产欧美| 精品999在线观看| 小小影院久久| 男女爽爽爽视频| 99久久精品情趣| 一区二区在线观看免费视频| 在线亚洲一区二区| 免费av一级片| 久久精品99久久久久久久久| 欧美片第一页| 国产一级精品aaaaa看| 久久人人99| 99免费视频观看| 91在线视频观看| 久久久久99精品成人片试看| 欧美色涩在线第一页| 天堂91在线| 欧美激情一级欧美精品| 国产精品一区三区在线观看| 神马影院我不卡午夜| 久久精品一区二区三区中文字幕| 色婷婷狠狠18禁久久| 中文字幕一区日韩精品欧美| 老熟妇一区二区三区| 亚洲国产精品成人精品| 三级资源在线| 成人国产精品一区二区| 精品久久美女| 国产最新免费视频| www.日韩av| 国产无精乱码一区二区三区| 精品国产一区二区三区久久影院| 成人欧美在线| 91麻豆国产精品| 天天影视欧美综合在线观看| 亚洲xxxx2d动漫1| 国产亚洲欧美在线| 亚洲欧美一二三区| 亚洲天堂色网站| 亚洲www免费| 欧美日韩一区二区视频在线观看 | av中文字幕一区二区| 虎白女粉嫩尤物福利视频| 26uuu亚洲婷婷狠狠天堂| 国产情侣在线视频| 国产偷亚洲偷欧美偷精品| 伊人久久综合一区二区| 日本黑人久久| 美国一区二区三区在线播放 | 九色porny在线| 成人福利在线视频| 伊人色**天天综合婷婷| 日韩av最新在线观看| 黄页在线观看免费| 成人一区二区三区四区| 国内精品99| 波多野结衣一二三区| 精品久久久一区| 欧美女v视频| 国产精品无av码在线观看| **女人18毛片一区二区| 天天操夜夜操很很操| 亚洲成人自拍一区| 你懂的在线免费观看| 国产精品视频男人的天堂| 91蜜臀精品国产自偷在线| 国产精品欧美性爱| 精品国产户外野外| 国产色在线 com| 亚洲精品日韩激情在线电影| 黄页网站一区| 亚洲最大成人网站| 欧美美女bb生活片| 国产一线二线在线观看| 色综合久久中文综合久久97| 国产裸体美女永久免费无遮挡| 日韩中文字幕欧美| 中文无码日韩欧| 麻豆av免费在线| 亚洲视频每日更新| 亚洲 欧美 自拍偷拍| 国产日韩精品在线播放| 亚洲黄网站黄| 欧美 日韩 成人| 欧美一级久久久| 日韩免费福利视频| 一本—道久久a久久精品蜜桃| 成人动漫av在线| 欧美国产一级片| 欧美激情啊啊啊| av伊人久久| 插我舔内射18免费视频| 欧美日韩亚洲综合在线 | 亚洲自拍第三页| 欧美视频免费在线观看| av免费网站在线| 茄子视频成人在线观看| 国产精品99久久久久久似苏梦涵| 麻豆成人免费视频| 欧美国产精品va在线观看| 成人激情视频| 你懂得在线视频|