SQL 入門

SQLite 入門

「以 Kotlin 開發 Android 應用程式」課程假設你已熟悉下列主題:

  • 資料庫的一般知識
  • 尤其是 SQL 資料庫
  • 用來與資料庫互動的 SQL 語言

這個頁面提供複習和快速參考指南。

SQL 資料庫

SQL 資料庫會將資料儲存在由資料列和資料欄組成的資料表中:

  • 資料列和資料欄的交集處稱為欄位
  • 欄位包含資料、對其他欄位的參照,或對其他資料表的參照。
  • 每一個資料列都包含一個實體。實體是透過一組專屬 ID 來識別,通常會用來當做主鍵
  • 每個資料欄透過每個資料表中的唯一名稱來識別。

SQLite

SQLite 實作的 SQL 資料庫引擎具有下列特性:

  • 獨立存在 (不需要其他元件)
  • 無伺服器 (不需伺服器後端)
  • 無須設定 (不必為應用程式進行設定)
  • 交易性 (SQLite 單一交易中的異動可能全面發生或完全不發生)

SQLite 是全球部署最廣泛的資料庫引擎。SQLite 的原始碼位於公有領域。如要進一步瞭解 SQLite 資料庫,請參閱 SQLite 網站

範例資料表

  • 名為 DATABASE_NAME 的資料庫
  • 名為 WORD_LIST_TABLE 的資料表
  • _idworddefinition 的資料欄

插入 alphabeta 這兩個字詞後 (其中 alpha 有兩個定義),資料表可能如下所示:

DATABASE_NAME

WORD_LIST_TABLE

_id

word

definition

1

"alpha"

"first letter"

2

"beta"

"second letter"

3

"alpha"

"particle"

如要尋找特定資料列中的資料,請使用 _id 或指定限制條件來設定查詢,以便從資料表選取資料列,進而完成資料列擷取作業。

交易

「交易」是指作為單一邏輯作業單元執行的一系列作業。如要符合交易資格,邏輯作業單元必須具備四個屬性:原子性、一致性、隔離性和耐用性 (ACID):

  • 原子性。全面執行交易的所有資料修改作業,或是完全不執行任何修改作業。即使程式停止運作、作業系統當機或電源故障,導致將變更寫入磁碟的動作中斷,原子性也會維持不變。
  • 一致性。交易完成後,交易必須讓所有資料維持一致狀態。
  • 隔離性。並行交易所做的修改必須與其他並行交易所做的修改隔離。交易可辨識資料受到另一個並行交易修改前的狀態,或者交易可在第二筆交易完成後辨識資料。交易無法辨識中間狀態。
  • 耐用性。交易完成後,相關效果會在系統中永久生效。即使發生系統故障,修改作業仍會持續。

交易範例:

  • 從儲蓄帳戶轉帳至支票帳戶。
  • 將字詞和定義輸入到字典中。
  • 將變更清單提交至主要分支版本。

如要進一步瞭解交易,請參閱 Atomic Commit In SQLite (SQLite 完整確認)。

查詢語言

你需要使用 SQL 查詢語言來與資料庫互動。查詢可能相當複雜,但有如下四種基本作業:

  • 插入資料列
  • 刪除資料列
  • 更新資料列中的值
  • 擷取符合特定條件的資料列

在 Android 上,資料存取物件 (DAO) 提供插入、刪除及更新資料庫的簡便方法。如需查詢語言的完整說明,請參閱 SQL As Understood By SQLite (SQLite 所理解的 SQL)。

查詢結構

SQL 查詢具有非常完整的結構。查詢範例:

  • SELECT word, definition FROM WORD_LIST_TABLE WHERE word="alpha"

查詢範例的一般版本:

  • SELECT 資料欄 FROM 資料表 WHERE 資料欄="值"

查詢範例的組成部分:

  • SELECT 資料欄:選取要傳回的資料欄。使用 * 傳回所有資料欄。
  • FROM 資料表:指定要從中取得結果的資料表。
  • WHERE:位於條件之前且必須符合的選用關鍵字,例如 資料欄="值"。常見的運算子包括 =LIKE<>。如要連結多個條件,請使用 ANDOR

查詢的其他部分:

  • ORDER BY:依據資料欄為結果排序的選用關鍵詞組。指定 ASC 表示遞增,DESC 表示遞減。如果你未指定順序,結果就會依照預設順序顯示 (可能是有序或無序)。
  • LIMIT:可指定有限數量結果的關鍵字。

查詢和結果範例

下列查詢會使用先前定義的資料表:

SELECT * FROM WORD_LIST_TABLE

取得 WORD_LIST_TABLE 資料表中的所有資料列。
SELECT word, definition FROM WORD_LIST_TABLE WHERE _id > 2 選取 id 大於 2 的所有項目的 worddefinition 資料欄。
傳回

[["alpha", "particle"]]

SELECT _id FROM WORD_LIST_TABLE WHERE word="alpha" AND definition LIKE "%art%"

傳回定義中包含子字串 artalpha 字詞的 id

[["3"]]

SELECT definition FROM WORD_LIST_TABLE ORDER BY word DESC LIMIT 1

選取所有定義。反向排序,並在清單排序後取得第一個資料列。排序依據為指定的 word 資料欄。請注意,我們可以依照未傳回的資料欄排序!

[["second letter"]]

SELECT * FROM WORD_LIST_TABLE LIMIT 2,1

從位置 2 開始傳回 1 個項目。位置計數從 1 開始 (不是零!)。傳回 [["2", "beta", "second letter"]]

如要練習建立及查詢資料庫,你可以前往這個 SQL Fiddle 網站

Android SQLite 的查詢

你可以將查詢傳送至 Android 系統的 SQLite 資料庫,做為原始查詢或參數。

rawQuery(String sql, String[] selectionArgs) 方法會執行所提供的 SQL。這個方法會傳回結果集的 Cursor。下表會顯示上述前兩個查詢範例當做原始查詢的樣貌:

1

String query = "SELECT * FROM WORD_LIST_TABLE";
rawQuery(query, null);

2

query = "SELECT word, definition FROM WORD_LIST_TABLE WHERE _id> ? ";
String[] selectionArgs = new String[]{"2"}
rawQuery(query, selectionArgs) ;

query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) 方法會查詢指定資料表。這個方法會透過結果集傳回 Cursor。以下查詢說明了如何填入引數:

SELECT * FROM WORD_LIST_TABLE
WHERE word="alpha"
ORDER BY word ASC LIMIT 2,1;

查詢傳回的結果如下:

[["alpha", "particle"]]

可使用的引數範例如下:

String table = "WORD_LIST_TABLE"
String[] columns = new String[]{"*"};
String selection = "word = ?"
String[] selectionArgs = new String[]{"alpha"};
String groupBy = null;
String having = null;
String orderBy = "word ASC"
String limit = "2,1"

query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit);

注意:在實際的程式碼中,你無法為 null 值建立變數。如要瞭解這個方法的不同參數版本,請參閱 Android SQLiteDatabase 說明文件。

游標

游標是指向結構化資料列的指標。你可以將游標視為指向資料表中資料列的指標。

查詢會傳回一個指向查詢結果中第一個元素的 Cursor 物件。Cursor 類別提供在查詢結果中移動游標的方法,以及從結果中每個資料列的資料欄取得資料的方法。

當方法傳回 Cursor 物件時,你可以疊代結果、擷取資料、運用資料執行操作,然後關閉游標來釋出記憶體。

瞭解詳情