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)
}

Swift - SQLite でデータを取得 (SELECT) 1


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))

Swift - SQLite でデータを取得 (SELECT) 2

student_id = 1 の student の情報が取得できています。


入力引数の studentId を 2 に変更して実行すると次のようになります。

Opened connection to database
Student not found

Swift - SQLite でデータを取得 (SELECT) 3


以上、Swift で SQLite のテーブルのデータを取得する方法をご説明しました。

次は Swift で SQLite のデータを削除します。

次の記事 「Swift - SQLite でデータを削除 (DELETE)」

© 2024 iOS 開発入門