技術ブログ

プログラミング、IT関連の記事中心

SQLiteの使用方法【Objective-C】

◾️はじめに

データを永続的に保存する方法で、数々の方法があります。
以下に一例を挙げます。
・NSUserDefaults
・CoreData
SQLite
・Realm

ここでは、「SQLite」に関して記載します。
SQL文に関しては、簡単なサンプルや記載方法は記載するが細かい部分は別途調査する事。

◾️SQLiteとは

SQLiteとは、数あるSQLの中の一つです。
※ちなみに、SQLとはDB(データベース)を定義したり操作したりするプログラミング言語です。

SQLiteの特徴として、他のSQLMySQL,Oracleなど)と違い、DBをファイル形式で保持する事ができます。
※他のSQLMySQL,Oracleなど)のほとんどは、サーバー上にDBを保持します。

上記の特徴があるため、ローカルにDBファイルを保存しておく事で、サーバーへ接続する必要がなくなるメリットがあります。

◾️SQLiteのインポート

SwiftでSQLiteを使用する為に、便利なライブラリが色々とありますが
ライブラリを使用したくない場合もありますよね。(現場の方針など。。。)

ここでは、ライブラリを使用しないSQLiteの操作を記載します。

まずは、SQLiteを操作する為に以下をインポートします。
SQLiteの操作をするクラスでは必ずインポートしてください。

ソースコードを記載する前に、「Linked Frameworks and Libraries」に「libsqlite3.0.tbd」を追加する必要がある。

@import SQLite3;

◾️DBファイルの定義

SQLiteとは」で説明した通り、SQLiteはDBをファイル形式で保持しています。
そのため、まずはDBファイルを生成する必要があります。

まずは、フィールド変数に、以下を定義してください。
※都度定義するのが手間なので、まとめて。

// SQLiteのファイル名
NSString *dataFileName;
// SQLiteのファイルまでのフルパス
NSString *dataFileFullPath;
// 開いているSQLiteファイルのインスタンス
sqlite3 *sqlax;

上記を定義したら、SQLiteの物理ファイルを生成します。
以下のメソッドを定義して、呼び出してください。

/**
 * SQLiteの物理ファイルの作成
 */
-(void)preparationOfPhysicalDiles {
    // 1.【物理ファイルを準備します】
    dataFileName = @"unkolist.sqlite3";

    // 使用可能なファイルパスを全て取得する
    NSArray *availablePats = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    // 最初のものを使用する
    NSString *dir = [availablePats objectAtIndex:0];
    // ファイルマネージャを召還する
    NSFileManager *myFM = [NSFileManager defaultManager];
    // 物理ファイルって既にありますか?
    dataFileFullPath = [dir stringByAppendingPathComponent:dataFileName];
    BOOL fileExists = [myFM fileExistsAtPath:dataFileFullPath];
    // 無い場合はつくる
    if (! fileExists) {
        BOOL isSuccessfullyCreated = [myFM createFileAtPath:dataFileFullPath contents:nil attributes:nil];
        if (! isSuccessfullyCreated) {
            NSLog(@"新規ファイル作成に失敗しました=>%@", dataFileFullPath);
        }
    }
}

ここまでの下準備ができたら、以下のメソッドを実行し、SQLiteを開きます。
※テーブル作成などを行う前に、一番最初に実行する必要があります。

/**
 * SQLiteを開くメソッド(※SQLの実行前には呼んでおく必要がある。)
 */
-(void)openSQLite {
    BOOL isSuccessfullyOpened = sqlite3_open([dataFileFullPath UTF8String], &sqlax);
    if (isSuccessfullyOpened != SQLITE_OK) {
        NSLog(@"sqlite開けませんでした!=> %s", sqlite3_errmsg(sqlax));
    }
}

これで、SQLiteを開く事ができたので、以降でDBの操作をします。

◾️Table作成(CREATE TABLE)

ここでは、テーブルの作成方法を記載します。

以下のメソッドを実行する事で、Tableの作成が可能です。
※以下のメソッドに記載しているSQL文は各自書き換えてください。

【テーブル作成のSQLの基本の記載方法】
CREATE TABLE [テーブル名] ([カラム名] [データ型], [カラム名] [データ型] ・・・)

/**
 * テーブル作成処理
 */
-(void)createTable {
    sqlite3_stmt *statement;

    // CREATE TABLE文 (「IF NOT EXISTS」を書くことで、既に作成されている場合には処理しない)
    NSString *query = @"CREATE TABLE IF NOT EXISTS sampleTable (name TEXT)";
    sqlite3_prepare_v2(sqlax, [query UTF8String], -1, &statement, nil);
    sqlite3_step(statement);
    sqlite3_finalize(statement);
}

◾️カラムの登録(INSERT)

ここでは、カラムの登録方法を記載します。

以下のメソッドを実行する事で、カラムの登録が可能です。
※以下のメソッドに記載しているSQL文は各自書き換えてください。

【カラムの登録のSQLの基本の記載方法】
INSERT INTO [テーブル名] ([カラム名], [カラム名]・・・) VALUES ([データ], [データ]・・・)

/**
 * データの追加処理
 */
-(void)insertData: (NSString*) name {
    sqlite3_stmt *statement;

    // INSERT
    NSString *query = [NSString stringWithFormat:@"INSERT INTO sampleTable (name) VALUES (\"%@\")", name];
    sqlite3_prepare_v2(sqlax, [query UTF8String], -1, &statement, nil);
    sqlite3_step(statement);
    sqlite3_finalize(statement);
}

◾️データの取得(SELECT)

ここでは、データの取得方法を記載します。

以下のメソッドを実行する事で、データの取得が可能です。
※以下のメソッドに記載しているSQL文は各自書き換えてください。
※取得したレコードのループ処理は各自書き換えてください。

【データの取得のSQLの基本の記載方法】
SELECT * FROM [テーブル名]

/**
 * データの検索処理
 */
-(void)selectData {
    sqlite3_stmt *statement;

    NSString *query = @"SELECT name FROM sampleTable";
    sqlite3_prepare_v2(sqlax, [query UTF8String], -1, &statement, nil);
    while (sqlite3_step(statement) == SQLITE_ROW) {
        char *ownerNameChars = (char *) sqlite3_column_text(statement,0);
        NSLog(@"Found : %s", ownerNameChars);
    }
    sqlite3_finalize(statement);
}

◾️データの更新(UPDATE)

ここでは、データの更新方法を記載します。

以下のメソッドを実行する事で、データの更新が可能です。
※以下のメソッドに記載しているSQL文は各自書き換えてください。

【データの更新のSQLの基本の記載方法】
UPDATE [テーブル名] SET [カラム名] = [データ] WHERE [カラム名] = [データ]

/**
 * データの更新処理
 */
-(void)updateData {
    sqlite3_stmt *statement;

    // UPDATE
    NSString *query = [NSString stringWithFormat:@"UPDATE sampleTable SET name = \"KONBANWA\" WHERE name = \"HELLO\""];
    sqlite3_prepare_v2(sqlax, [query UTF8String], -1, &statement, nil);
    sqlite3_step(statement);
    sqlite3_finalize(statement);
}

◾️データの削除(DELETE)

ここでは、データの削除方法を記載します。

以下のメソッドを実行する事で、データの削除が可能です。
※以下のメソッドに記載しているSQL文は各自書き換えてください。

【データの削除のSQLの基本の記載方法】
DELETE FROM [テーブル名] WHERE [カラム名] = [データ]

/**
 * データの削除処理
 */
-(void)deleteData {
    sqlite3_stmt *statement;

    // DELETE
    NSString *query = [NSString stringWithFormat:@"DELETE FROM sampleTable WHERE name = \"HELLOHELLO\""];
    sqlite3_prepare_v2(sqlax, [query UTF8String], -1, &statement, nil);
    sqlite3_step(statement);
    sqlite3_finalize(statement);
}

◾️SQLiteを閉じる

以下のメソッドを実行する事で、SQLiteを閉じる事ができます。
SQLの処理が終わって、不要になれば閉じるようにしましょう。

/**
 * SQLiteを閉じるメソッド(※SQLの実行後に呼ぶ必要がある。)
 */
-(void)closeSQLite {
    // SQLiteを閉じる
    sqlite3_close(sqlax);
}

◾️さいごに

色々と、書きましたが、私が動作確認で実行したソースを以下に記載しておきます。

#import "SQLiteViewController.h"
@import SQLite3;

@interface SQLiteViewController () {
    // SQLiteのファイル名
    NSString *dataFileName;
    // SQLiteのファイルまでのフルパス
    NSString *dataFileFullPath;
    // 開いているSQLiteファイルのインスタンス
    sqlite3 *sqlax;
}

@end

@implementation SQLiteViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // SQLiteの物理ファイルの生成
    [self preparationOfPhysicalDiles];
    // SQLiteを開く
    [self openSQLite];
    
    // テストでいくつかのSQLを実行する
    [self test];
    
    // SQLiteを閉じる
    [self closeSQLite];
}

/**
 * テストで適当なSQLを実行する
 */
-(void)test {
    // CREATE TABLE
    [self createTable];
    
    // INSERT
    [self insertData:@"HELLO"];
    [self insertData:@"HELLOHELLO"];
    [self insertData:@"HELLOHELLOHELLO"];
    
    // UPDATE
    [self updateData];
    
    // DELETE
    [self deleteData];
    
    // SELECT
    [self selectData];
}

/**
 * SQLiteの物理ファイルの作成
 */
-(void)preparationOfPhysicalDiles {
    // 1.【物理ファイルを準備します】
    dataFileName = @"unkolist.sqlite3";
    
    // 使用可能なファイルパスを全て取得する
    NSArray *availablePats = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    // 最初のものを使用する
    NSString *dir = [availablePats objectAtIndex:0];
    // ファイルマネージャを召還する
    NSFileManager *myFM = [NSFileManager defaultManager];
    // 物理ファイルって既にありますか?
    dataFileFullPath = [dir stringByAppendingPathComponent:dataFileName];
    BOOL fileExists = [myFM fileExistsAtPath:dataFileFullPath];
    // 無い場合はつくる
    if (! fileExists) {
        BOOL isSuccessfullyCreated = [myFM createFileAtPath:dataFileFullPath contents:nil attributes:nil];
        if (! isSuccessfullyCreated) {
            NSLog(@"新規ファイル作成に失敗しました=>%@", dataFileFullPath);
        }
    }
}

/**
 * SQLiteを開くメソッド(※SQLの実行前には呼んでおく必要がある。)
 */
-(void)openSQLite {
    BOOL isSuccessfullyOpened = sqlite3_open([dataFileFullPath UTF8String], &sqlax);
    if (isSuccessfullyOpened != SQLITE_OK) {
        NSLog(@"sqlite開けませんでした!=> %s", sqlite3_errmsg(sqlax));
    }
}

/**
 * SQLiteを閉じるメソッド(※SQLの実行後に呼ぶ必要がある。)
 */
-(void)closeSQLite {
    // SQLiteを閉じる
    sqlite3_close(sqlax);
}

/**
 * テーブル作成処理
 */
-(void)createTable {
    sqlite3_stmt *statement;
    
    // CREATE TABLE文 (「IF NOT EXISTS」を書くことで、既に作成されている場合には処理しない)
    NSString *query = @"CREATE TABLE IF NOT EXISTS sampleTable (name TEXT)";
    sqlite3_prepare_v2(sqlax, [query UTF8String], -1, &statement, nil);
    sqlite3_step(statement);
    sqlite3_finalize(statement);
}

/**
 * データの追加処理
 */
-(void)insertData: (NSString*) name {
    sqlite3_stmt *statement;
    
    // INSERT
    NSString *query = [NSString stringWithFormat:@"INSERT INTO sampleTable (name) VALUES (\"%@\")", name];
    sqlite3_prepare_v2(sqlax, [query UTF8String], -1, &statement, nil);
    sqlite3_step(statement);
    sqlite3_finalize(statement);
}

/**
 * データの更新処理
 */
-(void)updateData {
    sqlite3_stmt *statement;
    
    // UPDATE
    NSString *query = [NSString stringWithFormat:@"UPDATE sampleTable SET name = \"KONBANWA\" WHERE name = \"HELLO\""];
    sqlite3_prepare_v2(sqlax, [query UTF8String], -1, &statement, nil);
    sqlite3_step(statement);
    sqlite3_finalize(statement);
}

/**
 * データの削除処理
 */
-(void)deleteData {
    sqlite3_stmt *statement;
    
    // DELETE
    NSString *query = [NSString stringWithFormat:@"DELETE FROM sampleTable WHERE name = \"HELLOHELLO\""];
    sqlite3_prepare_v2(sqlax, [query UTF8String], -1, &statement, nil);
    sqlite3_step(statement);
    sqlite3_finalize(statement);
}

/**
 * データの検索処理
 */
-(void)selectData {
    sqlite3_stmt *statement;
    
    NSString *query = @"SELECT name FROM sampleTable";
    sqlite3_prepare_v2(sqlax, [query UTF8String], -1, &statement, nil);
    while (sqlite3_step(statement) == SQLITE_ROW) {
        char *ownerNameChars = (char *) sqlite3_column_text(statement,0);
        NSLog(@"Found : %s", ownerNameChars);
    }
    sqlite3_finalize(statement);
}
@end