Swift で SQLite のテーブルを作成する

ここでは、Swift で SQLite のテーブルを作成する方法をご説明します。

Swift で SQLite データベースを作成して開く」のコードに、SQLite のテーブルを作成するコードを追加します。


次のような Student 構造体のデータを保持する SQLite のテーブルを作成します。

import Foundation

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

メニューから File > New > File...[iOS][Swift File] を選択し、Student.swift という名前でファイルを作成し、上のコードを追加しておきます。

Swift で SQLite のテーブルを作成する 1


Swift で SQLite データベースを作成して開く」では、DBService クラスのイニシャライザーで SQLite のデータベースを作って開き、db ハンドルを取得しました。

今回はその後に SQLite のテーブルを作成するコードを追加します。


DBService.swift ファイルを開き以下のコードを追加してください。

import Foundation
import SQLite3

final class DBService {
    static let shared = DBService()
    
    private let dbFile = "DBVer1.sqlite"
    private var db: OpaquePointer?
    
    private init() {
        db = openDatabase()
        if !createTable() {
            print("Failed to create table")
        }
    }
    
    private func openDatabase() -> OpaquePointer? {
        let fileURL = try! FileManager.default.url(for: .documentDirectory,
                                                   in: .userDomainMask,
                                                   appropriateFor: nil,
                                                   create: false).appendingPathComponent(dbFile)
        
        var db: OpaquePointer? = nil
        if sqlite3_open(fileURL.path, &db) != SQLITE_OK {
            print("Failed to open database")
            return nil
        }
        else {
            print("Opened connection to database")
            return db
        }
    }
    
    private func createTable() -> Bool {
        let createSql = """
        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
        );
        """
        
        var createStmt: OpaquePointer? = nil
        
        if sqlite3_prepare_v2(db, (createSql as NSString).utf8String, -1, &createStmt, nil) != SQLITE_OK {
            print("db error: \(getDBErrorMessage(db))")
            return false
        }
        
        if sqlite3_step(createStmt) != SQLITE_DONE {
            print("db error: \(getDBErrorMessage(db))")
            sqlite3_finalize(createStmt)
            return false
        }
        
        sqlite3_finalize(createStmt)
        return true
    }
    
    private func getDBErrorMessage(_ db: OpaquePointer?) -> String {
        if let err = sqlite3_errmsg(db) {
            return String(cString: err)
        } else {
            return ""
        }
    }
}

Swift で SQLite のテーブルを作成する 2

コードを順を追ってご説明します。

12 行目のイニシャライザーの中で、createTable() 関数を呼んで、false を返した場合は、失敗したというメッセージをプリントしています。


34 ~ 63 行目で createTable() 関数を定義しています。

まず、35 ~ 43 行目で、SQLite の CREATE TABLE 文のスクリプトを createSql に定義しています。

CREATE TABLE IF NOT EXISTS で、students テーブルが存在しない時のみテーブルを作成するようにしています。

カラムは Student 構造体のあわせた名前と SQLite のデータ型を指定しています。


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 */
);

45 行目で、sqlite3_prepare_v2() 関数に渡すステートメントハンドル用の OpaquePointer? 型の変数の createStmt を定義しています。

47 行目で、sqlite3_prepare_v2() 関数に、データベースを開いた時に取得した db ハンドル、SQL文を UTF-8 に変換した文字列、上で定義した &createStmt などを渡して実行しています。


sqlite3_prepare_v2() 関数 は成功したら SQLITE_OK を返し、失敗するとエラーコードを返します。

失敗した時には getDBErrorMessage() 関数を使ってエラーコードをプリントし、false を返しています。


先に 62 ~ 68 行目の getDBErrorMessage() 関数を説明します。

エラーコードを取得するのに sqlite3_errmsg() 関数を使います。

sqlite3_errmsg() 関数は db ハンドルを受け取り 最後に失敗した API コールのエラーメッセージを返す関数です。

getDBErrorMessage() 関数では sqlite3_errmsg() 関数を使って、エラーメッセージを取得し、それを元に Swift の String を生成して返しています。


元に戻って、52 ~ 56 行目では、sqlite3_step() 関数を使って、コンパイルした SQL文を評価して実行しています。

sqlite3_step() 関数は成功すると SQLITE_DONE を返します。

失敗した時は getDBErrorMessage() 関数を使ってエラーコードをプリントしています。

return する前に、sqlite3_finalize() 関数で、prepare したステートメントオブジェクトを destroy しています。


58 ~ 59 行目では、ステートメントの実行が成功した時にも sqlite3_finalize() 関数で、prepare したステートメントオブジェクトを destroy してから true を返しています。


以上、Swift で SQLite のテーブルを作成する方法をご説明しました。

次は Swift で SQLite のテーブルにデータを挿入します。

次の記事 「Swift - SQLite でデータを挿入 (INSERT)」

© 2024 iOS 開発入門