Using SQLite: Update The Database Records

Last week you learned how to fetch records from the database’s possession table and display them in the Master View’s Table View control. Today you’ll learn how to update a record in the database’s possessions table via the Detail view.

The SQL UPDATE Statement

This statement update a single record or multiple records in a SQLite database table. The UPDATE statement returns no result and has this general syntax:

UPDATE table-name
SET column-name = new-value, column_name = new-value, ...
WHERE condition

Which records are updated is determined by the condition in the WHERE clause. The condition is tested against each record of the table. The most common condition use the equality condition to check a unique column, such as a PRIMARY KEY column.

Example 1

Say you created a table called employees in the application’s database file and inserted these records in it.

sqlitedemo-fig32

Now, you want to change the last record’s department value from “Human Resource” to “Marketing”. To do so you’d use the sqlite3_execute() function to prepare, step, and finalize this SQL statement:

const char *sqlStatement = "UPDATE employees SET department = 'Marketing' WHERE empId = 4042";

Above query will update a single record that satisfies the condition in the WHERE clause. If there are multiple records (or rows) that satisfy the condition, all of them will be modified. If no WHERE clause is specified, all values in the “department” column will be modified. In other words; the “department” column values for all six records will be replace with the text, Marketing.

tip_iconWhen you write an UPDATE query, make sure you set up the WHERE condition correctly to avoid lose of vital data.

Update a Record in The possessions Table

Now that you’ve been introduced to SQL’s UPDATE statement, you are ready to use it in the SqliteDatabase application to enable the app user to update one or more records in the itemsOwned’s possessions table. Assume the table currently have these records.

sqlitedatabase-fig17

Say you wanted to change the third record’s item name and description, you’d have to first declare and implement this method in the AppDelegate class, which update the record in the database belonging to the oldItemName passed to the method as a parameter.

- (void)updatePossession:(NSString *)oldItemName field2:(Item *)formData;
{
  const char *sql = "UPDATE possessions SET name=?, description=?, photo=? WHERE name=?";
  sqlite3_stmt *compiledStatement;

  //1. Prepare the sql statement
  int result = sqlite3_prepare_v2(dbHandle, sql, -1, &compiledStatement, NULL);

  const char *newName = [formData.itemName UTF8String];
  const char *newDescription = [formData.itemDescription UTF8String];
  const char *dbName = [oldItemName UTF8String];

  //2. Bind the method's parameters
  sqlite3_bind_text(compiledStatement, 1, [formData.itemName UTF8String], -1, NULL);
  sqlite3_bind_text(compiledStatement, 2, [formData.itemDescription UTF8String], - 1, NULL);
  NSData *imageData = UIImagePNGRepresentation(formData.itemImage);
  sqlite3_bind_blob(compiledStatement, 3, [imageData bytes], [imageData length], NULL);
  sqlite3_bind_text(compiledStatement, 4, [formData.itemName UTF8String], -1, NULL);

  if(result != SQLITE_OK) {
    NSLog(@"updatePossession method error:\n%s", sqlite3_errmsg(dbHandle));
  }

  //3. Execute the sql statement
  result = sqlite3_step(compiledStatement);
  if (result != SQLITE_DONE) {
    NSLog(@"updatePossession method error:\n%s", sqlite3_errmsg(dbHandle));
  }

  //3. Finalize the prepared statement
  sqlite3_finalize(compiledStatement);
}

The second thing you’ll have to do is, declare this property in the DetailViewController.h file:

@property (strong, nonatomic) AppDelegate *appDelegate;

Next, add highlighted code in the DetailViewController.m file’s viewDidLoad method.

- (void)viewDidLoad
{
  [super viewDidLoad];
  self.appDelegate = [[UIApplication sharedApplication] delegate];

  // Populate the view's controls
  self.itemName.text = self.dbItem.itemName;
  self.itemDescription.text = self.dbItem.itemDescription;
  self.imageView.image = self.dbItem.itemImage;

  self.oldItemName = self.dbItem.itemName;
}

Now, add this code in the DetailViewController.m file’s updateButtonTapped: method.

- (IBAction)updateButtonTapped:(UIBarButtonItem *)sender {
  // Trim itemName field
  NSString *cleanString = [self.itemName.text stringByTrimmingCharactersInSet:
  [NSCharacterSet whitespaceAndNewlineCharacterSet]];

  // Open the database
  [self.appDelegate openDatabase];

  if (cleanString.length == 0) {
    // Display an Alert View
    UIAlertView *alert = [[UIAlertView alloc]
    initWithTitle:@"Required Data Missing."
    message:@"Item Name"
    delegate: nil
    cancelButtonTitle: @"OK"
    otherButtonTitles: nil];
   [alert show];
  } else {
    // Query the database
    if ([self.appDelegate checkForDuplicateEntry:self.itemName.text]) {
      // Display an Alert View
      UIAlertView *alert = [[UIAlertView alloc]
      initWithTitle:@"Save Failed"
      message:@"The item Name already exists in the database."
      delegate: nil
      cancelButtonTitle: @"OK"
      otherButtonTitles: nil];
      [alert show];
    } else {
     // Reset the dbItem object's properties
     self.dbItem.itemName = self.itemName.text;
     self.dbItem.itemDescription = self.itemDescription.text;
     self.dbItem.itemImage = self.imageView.image;

      // Update a record in the database
      [self.appDelegate updatePossession:self.oldItemName field2:self.dbItem];

      // Perform a segue which return the user back to the Master view
      [self performSegueWithIdentifier:@"gotoMasterView" sender:self];
   }
  }
  // Close the database
  [self.appDelegate closeDatabase];
}

Here is the code to add in the chooseImageButtonTapped method.

- (IBAction)chooseImageButtonTapped {
  UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];

  // Set the imagePicker delegate so we can use its delegate methods
  imagePicker.delegate = self;

  // Set the imagePicker object to access the Photos app's Photo Library
  imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

  // Launch the Photos app
  [self presentViewController:imagePicker animated:YES completion:nil];
}

Finally, here’s the code to implement two methods of the UIImagePickerControllerDelegate class.

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
  // Declare an image object, set it to the image the user picked
  UIImage *chosenImage = [info valueForKey:UIImagePickerControllerOriginalImage];

  // Set the view's ImageView control's Image property with the image the user picked
  self.imageView.image = chosenImage;

  // The user finished picking an image, so dismiss the imagePicker
  [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
  // The user tapped the imagePicker's Cancel button, so dismiss the imagePicker
  [self dismissViewControllerAnimated:YES completion:Nil];
}

Run The Application

When you are done, run the application, click the view’s table row to load the items detail in the Detail View, modify the view’s Item Name and Item Description Text Field controls, then click the navigation bar’s Update button. The app will update the record in the database file, then display the Master View in the simulator’s window. You know the item was updated because the new item name is shown in the Master View’s Table View control.

This conclude this week’s workshop. Next week, you’ll learn how to delete a record from the application’s database file and the Master View’s Table View control.