Swift - SQLite でデータを取得 (SELECT)
ここでは、Swift で SQLite のテーブルからデータを取得する方法をご説明します。
「Swift - SQLite でデータを更新 (UPDATE)」のコードに、SQLite でデータを取得するコードを追加します。
students テーブルのデータを取得する関数を定義する
前回は次のような Student 構造体のデータを保持する SQLite の students テーブルのデータを更新しました。
struct Student {
var StudentID: Int
var StudentNumber: String
var FirstName: String
var LastName: String
var Age: Int?
init(studentID: Int, studentNumber: String, firstName: String, lastName: String, age: Int?) {
self.StudentID = studentID
self.StudentNumber = studentNumber
self.FirstName = firstName
self.LastName = lastName
self.Age = age
}
}
CREATE TABLE IF NOT EXISTS students (
student_id INTEGER NOT NULL PRIMARY KEY,
student_number TEXT NOT NULL,
first_name TEXT NULL,
last_name TEXT NULL,
age INTEGER NULL
);
今回は、StudentID を指定して、students テーブルからデータを取得する getStudent 関数を作ります。
DBService.swift ファイルを開き以下のコードを追加してください。
func getStudent(studentId: Int) -> (success: Bool, errorMessage: String?, student: Student?) {
var student: Student? = nil
let sql = """
SELECT student_id, student_number, first_name, last_name, age
FROM students
WHERE student_id = ?;
"""
var stmt: OpaquePointer? = nil
if sqlite3_prepare_v2(db, (sql as NSString).utf8String, -1, &stmt, nil) != SQLITE_OK {
return (false, "Unexpected error: \(getDBErrorMessage(db)).", student)
}
sqlite3_bind_int(stmt, 1, Int32(studentId))
if sqlite3_step(stmt) == SQLITE_ROW {
let studentID = Int(sqlite3_column_int(stmt, 0))
let studentNumber = String(describing: String(cString: sqlite3_column_text(stmt, 1)))
let firstName = String(describing: String(cString: sqlite3_column_text(stmt, 2)))
let lastName = String(describing: String(cString: sqlite3_column_text(stmt, 3)))
var age: Int?
if (sqlite3_column_type(stmt, 4) == SQLITE_NULL) {
age = nil
} else {
age = Int(sqlite3_column_int(stmt, 4))
}
student = Student(studentID: studentID, studentNumber: studentNumber,
firstName: firstName, lastName: lastName, age: age)
}
sqlite3_finalize(stmt)
return (true, nil, student)
}
getStudent 関数のコードを順を追ってご説明します。
入力引数は Int 型の studentID で、戻り値は (success: Bool, errorMessage: String?, student: Student?) のタプルです。
まず、5 ~ 9 行目で、SQLite の SELECT 文のスクリプトを sql に定義しています。
SQLite で SQL 文を実行するには、その前にステートメントを準備用の関数をつかって、バイトコードプログラムにコンパイルする必要があります。
ここでは、sqlite3_prepare_v2() 関数を使って SQL 文をコンパイルしています。
int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
11 行目で、sqlite3_prepare_v2() 関数に渡すステートメントハンドル用の OpaquePointer? 型の変数の stmt を定義しています。
12 行目で、sqlite3_prepare_v2() 関数に、データベースを開いた時に取得した db ハンドル、sql を UTF-8 に変換した文字列、上で定義した &stmt などを渡して実行しています。
sqlite3_prepare_v2() 関数 は成功したら SQLITE_OK を返し、失敗するとエラーコードを返します。
失敗した時には getDBErrorMessage() 関数を使ってエラーコードをプリントし、false を返しています。
16 行目で、sqlite3_bind_int() を使って、sql の ? に studentID を Int32 に変換してバインドしています。
18 行目で、sqlite3_step() 関数を使って、コンパイルした SQL文を評価して実行しています。
sqlite3_step() 関数はクエリーがデータを返すと、SQLITE_ROW を返します。
データが返った時は、19 ~ 32 行目でクエリー結果の値を取得しています。
19 行目では sqlite3_column_int() を使って、一つ目の値を studentID に取得しています。
20 ~ 22 行目では sqlite3_column_text() を使って、二つ目、三つ目、四つ目の値を studentNumber、firstName、lastName に取得しています。
age は NULL になる可能性があるので、24 ~ 29 行目では sqlite3_column_type() でデータ型を確認して NULL の時は、nil を、そうでない時は sqlite3_column_int() を使って値を age に代入しています。
31 ~ 32 行目で取得した値を元に student オブジェクトを生成しています。
指定した studentID を持つレコードが students テーブルに存在しなかった時は、student は nil のままになります。
35、36 行目で、sqlite3_finalize() 関数で、prepare したステートメントオブジェクトを destroy してから、生成した student オブジェクトなどを返しています。
students テーブルのデータを取得する
それでは、作った getStudent() 関数を使って、データを取得してみます。
前回、「Swift - SQLite でデータを更新 (UPDATE)」で更新した student_id = 1 のデータを取得します。
ViewController.swift の viewDidLoad() のコードを次のように変更してください。
//var student1 = Student(studentID: 1, studentNumber: "S000001", firstName: "Yuta", lastName: "Tanaka", age: 16)
//
//if DBService.shared.insertStudent(student: student1) {
// print("Insert success")
//} else {
// print("Insert Failed")
//}
//
//student1.LastName = "Yamada"
//student1.Age = 17
//
//if DBService.shared.updateStudent(student: student1) {
// print("Update success")
//} else {
// print("Update Failed")
//}
let (success, errorMessage, student) = DBService.shared.getStudent(studentId: 1)
if(success){
if let student = student {
print(student)
} else {
print("Student not found")
}
} else {
print(errorMessage ?? "Error")
}
18 行目で DBService.shared.getStudent(studentId: 1) を実行して、タプルに戻り値を取得しています。
succes が True で student が nil でない時は student を print しています。
student が nil の時は "Student not found" を、success が False の時はエラーメッセージを print しています。
これを実行すると、デバッガーのアウトプットコンソールに次のように表示されます。
Opened connection to database
Student(StudentID: 1, StudentNumber: "S000001", FirstName: "Yuta", LastName: "Yamada", Age: Optional(17))
student_id = 1 の student の情報が取得できています。
入力引数の studentId を 2 に変更して実行すると次のようになります。
Opened connection to database
Student not found
以上、Swift で SQLite のテーブルのデータを取得する方法をご説明しました。
次は Swift で SQLite のデータを削除します。