iPhoneでSQLite3を使う4(データの削除とバインド変数)
今回は、削除についてです。SQLではDELETE文を使います。
DELETE文の例
DELETE文では、どのテーブルを削除したいかを記述します。また、削除するときにこんなデータだけ削除するという、条件をつけることもできます。
DELETE FROM TABLE名 WHERE 条件
例えば、userinfoテーブルから、すべてのデータを削除したいのであれば、条件をつけずに
DELETE FROM userinfo
となります。
userinfoテーブルから、friends_countが10000以上のものだけを削除するなら
DELETE FROM userinfo WHERE friends_count >= 10000
となります。
Objective-Cでの実装を書くと下記のようになります。前回のSELECT文と使うメソッドは同じなので解説は省きます。DELETE文の場合は、値を取得するわけではないので成功か失敗だけを見れば良いです。
-(BOOL)userInfoDeleteAll { // 削除用 SQL 文を作成 NSString *deleteSQL = @"DELETE FROM userInfo"; // SQL文のコンパイルと実行 sqlite3_stmt *statement = Nil; if( sqlite3_prepare_v2(db_, [deleteSQL UTF8String], -1, &statement, NULL ) != SQLITE_OK) { NSLog( @"Failed to prepare statement with '%s'.", sqlite3_errmsg( db_ )); return NO; } int wasSucceeded = sqlite3_step(statement); //PREPARE済みSTATEMENTの廃棄 sqlite3_finalize(statement); if( wasSucceeded != SQLITE_DONE ) { NSLog( @"Failed to delete from database with '%s'.", sqlite3_errmsg( db_ )); return NO; } return YES; }
次は、指定のIDのみを削除する例です。引数にとして渡されたidを、SQLのwhere句に条件として指定します。
-(BOOL)userInfoDeleteID:(NSString*)id { // 削除用 SQL 文を作成 NSString *deleteSQL = [NSString stringWithFormat:@"DELETE FROM userInfo WHERE id = %@", id]; // SQL文のコンパイルと実行 sqlite3_stmt *statement = Nil; if( sqlite3_prepare_v2(db_, [deleteSQL UTF8String], -1, &statement, NULL ) != SQLITE_OK) { NSLog( @"Failed to prepare statement with '%s'.", sqlite3_errmsg( db_ )); return NO; } int wasSucceeded = sqlite3_step(statement); //PREPARE済みSTATEMENTの廃棄 sqlite3_finalize(statement); if( wasSucceeded != SQLITE_DONE ) { NSLog( @"Failed to delete from database with '%s'.", sqlite3_errmsg( db_ )); return NO; } return YES; }
userInfoDeleteAllと同じですね。
次のuserInfoDeleteIDを見てください。さきほどのuserInfoDeleteIDとやれることは同じです。何が違うのでしょう?
sqlite3_stmt* statementDelete_; -(BOOL)userInfoDeleteID:(NSString*)id { sqlite3_reset(statementDelete_); sqlite3_bind_text(statementDelete_, 1, [id UTF8String], -1, SQLITE_TRANSIENT); int wasSucceeded = sqlite3_step(statementDelete_); if( wasSucceeded != SQLITE_DONE ) { NSLog( @"Failed to delete from database with '%s'.", sqlite3_errmsg( db_ )); return NO; } return YES; } -(BOOL)prepareSQL { NSString* deleteSQL = @"delete from userInfo where id = ?"; if(sqlite3_prepare_v2(db_, [deleteSQL UTF8String], -1, &statementDelete_, NULL) != SQLITE_OK) { NSLog( @"Failed to prepare statement with '%s'.", sqlite3_errmsg( db_ )); return NO; } } -(void)finalizeSQL { if (db_) { // PREPARE済みSTATEMENTの廃棄 sqlite3_finalize(statementDelete_); } }
使い方のイメージは、こんな感じです。
[self prepareSQL]; for ( ) { [self userInfoDeleteID:xxx]; } [self finalizeSQL];
prepareSQLメソッドのSQL文を見てください。"?"という文字が入っています。これは、バインド変数といいます。prepareSQL実行時には値が決まっておらず、SQL実行時に値が決まるということを意味します。
では値はどこで決まっているかというと、sqlite3_bind_textというメソッドがあると思います。ここでセットしています。
sqlite3_bind_text(statementDelete_, 1, [id UTF8String], -1, SQLITE_TRANSIENT);
1というのが何番目の"?"かを意味して、そこに id の値をセットしてねということになります。
で、何がいいのか?
何度も実行する場合にメリットがあります。SQLはコンパイルする必要がある。sqlite3_prepare_v2でコンパイルするといいました。SQLをコンパイルする時に、そのテーブルの存在、指定の列が存在するのかチェックしたり結構な手間がかかります。バインド変数を使うとSQLのコンパイルが1回で済むので、パフォーマンス上のメリットがあるということになります。