小巧、快速、可靠。
任選三項。
確定性 SQL 函數

1. 概觀

SQLite 中的 SQL 函數可以是「確定性」或「非確定性」。

確定性函數在輸入相同時,總是會給出相同的答案。SQLite 中大多數內建的 SQL 函數都是確定性的。例如,abs(X) 函數只要輸入 X 相同,就會總是傳回相同的答案。

非確定性函數在每次呼叫時,即使參數都相同,也可能會給出不同的答案。以下是非確定性函數的範例:

由於 random() 函數每次呼叫都會給出不同的答案,因此顯然是非確定性的。changes()last_insert_rowid() 的答案會根據先前的 SQL 陳述而定,因此也是非確定性的。sqlite3_version() 函數大部分時間都是常數,但它會在 SQLite 升級時變更,因此即使它在特定階段總是傳回相同的答案,但由於它在不同階段會傳回不同的答案,因此仍被視為非確定性。

2. 非確定性函數使用限制

SQLite 中有一些情況不允許使用非確定性函數

在上述情況中,函數傳回的值會影響儲存在資料庫檔案中的資訊。CHECK 約束中的函數值會決定哪些項目對資料表有效,而部分索引的 WHERE 子句中的函數或表達式索引中的函數會計算儲存在索引 b-tree 中的值。如果這些函數稍後傳回不同的值,資料庫可能不再良好。因此,為了避免資料庫損毀,只有確定性函數才能用於上述情況中。

3. 日期/時間函數的特殊情況處理

SQLite 的內建 日期和時間函數 是特殊情況。這些函數通常被視為確定性的。但是,如果這些函數使用字串「now」作為日期,或者如果它們使用 localtime 修改器utc 修改器,則它們被視為非確定性的。由於函數輸入不一定在執行時間之前已知,因此如果日期/時間函數在僅允許確定性函數的環境中遇到任何非確定性功能,它們將擲回例外狀況。

在 SQLite 3.20.0 (2017-08-01) 之前,所有日期/時間函數都被視為非確定性的。日期/時間函數有時可以是確定性的,有時則根據其引數是非確定性的功能,已新增至 3.20.0 版本。

3.1. 版本 3.35.2 中的錯誤修正

當 SQLite 3.20.0 的強化功能讓日期/時間函數被視為確定性函數(因為它們不依賴於目前時間)時,有一個案例被遺漏:許多日期/時間函數可以在完全沒有參數的情況下呼叫。這些沒有參數的日期/時間函數的行為就像它們有一個單一的「'now'」參數。因此「datetime()」和「datetime('now')」都會產生目前的日期和時間。然而,只有第二種形式被識別為非確定性。這表示開發人員可以偷偷將非確定性的「datetime()」形式加入 CHECK 約束、索引表達式、產生欄位表達式,以及其他非確定性函數沒有意義的類似位置。這個疏忽在版本 3.35.2(2021-03-17)中獲得修正。然而,可能有舊版資料庫仍在流通,它們是由 SQLite 版本 3.20.0 到 3.35.1 建立,並且在它們的架構中具有非確定性的日期/時間函數。

4. 應用程式定義的確定性函數

預設情況下,應用程式定義的 SQL 函數被視為非確定性。然而,如果 sqlite3_create_function_v2() 的第 4 個參數與 SQLITE_DETERMINISTIC 進行 OR 運算,則 SQLite 會將該函數視為確定性函數。

請注意,如果一個非確定性函數被標記為 SQLITE_DETERMINISTIC,並且該函數最後被用於 部分索引表達式索引 的 WHERE 子句中,那麼當該函數開始傳回不同的答案時,相關的索引可能會損毀。如果一個 SQL 函數幾乎是確定性的(也就是說,它只會很少改變,例如 sqlite_version()),並且它被用於一個損毀的索引中,則損毀可以透過執行 REINDEX 來修復。

建構一個函數所需的介面,該函數有時會根據其輸入而確定性,有時則為非確定性,例如內建的日期/時間函數,尚未發布。通用的 應用程式定義的 SQL 函數 必須永遠是確定性或永遠是非確定性。

此頁面最後修改於 2022-01-08 05:02:57 UTC