how to check item already exits in sqlite objective c - ios

This the my code
NSString *query1 =[NSString stringWithFormat:#"select * from table name where item_name=%#",trimmedString];
// [self.dbManager executeQuery:query1];
// -(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable
NSLog(#"q1--%#",query1);
BOOL recordExist = [self.dbManager recordExistOrNot:query1];
NSLog(#"------%d",recordExist);
if (!recordExist)
{
NSString *query;
if (self.recordIDToEdit == -1) {
query = [NSString stringWithFormat:#"insert into c values(null,'%#','%d','%d',%d)",item_name.text,a,p,c];
NSLog(#"query---%#",query);
}
// Execute the query.
[self.dbManager executeQuery:query];
// If the query was successfully executed then pop the view controller.
if (self.dbManager.affectedRows != 0) {
NSLog(#"Query was executed successfully. Affected rows = %d", self.dbManager.affectedRows);
// UIAlertView *alert=[[UIAlertView alloc]initWithTitle:Nil message:#"Successfully Added to The Cart" delegate:Nil cancelButtonTitle:#"ok" otherButtonTitles:Nil, nil];
// [alert show];
[self loadData];
}
else{
NSLog(#"Could not execute the query.");
}
}
else
{
NSLog(#"item already exits....");
}
- (BOOL)recordExistOrNot:(NSString *)query1{
sqlite3 *sqlite3Database;
NSString *databasePath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
sqlite3_stmt *compiledStatement;
BOOL recordExist=NO;
if(sqlite3_open([databasePath UTF8String], &sqlite3Database) == SQLITE_OK)
{
// sqlite3_stmt *statement;
if (sqlite3_prepare_v2(sqlite3Database,[query1 UTF8String], -1, &compiledStatement, NULL)==SQLITE_OK)
{
if (sqlite3_step(compiledStatement)==SQLITE_ROW)
{
recordExist=YES;
}
else
{
//////NSLog(#"%s,",sqlite3_errmsg(database));
}
sqlite3_finalize(compiledStatement);
sqlite3_close(sqlite3Database);
}
}
return recordExist;
}
actually i want to be check string value in the table like "select * from table name where item_name=tea"
but this code is checking integer value but i want check string value.please help me

You are missing the single quotes in you select statement. first line.
NSString *query1 =[NSString stringWithFormat:#"select * from table name where item_name=%#",trimmedString];
to
NSString *query1 =[NSString stringWithFormat:#"select * from table name where item_name='%#'",trimmedString];

i'll assume that item_name is unique then you might be better served with doing insert or ignore.
i.e.
insert or ignore into tablename (item_name) values ('something')
thsi will ignore doing the insert if that value for your key exists

Related

ios Sqlite connectivity

my problem is that i am trying to connect my database to sqlite . it always with an error "table not found".. what should i do now .. plz help
here is my code for opendatabaseconnectivity....
BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
if(openDatabaseResult == SQLITE_OK) {
// Declare a sqlite3_stmt object in which will be stored the query after having been compiled into a SQLite statement.
sqlite3_stmt *compiledStatement;
// Load all data from database to memory.
BOOL prepareStatementResult = sqlite3_prepare_v2(sqlite3Database, query, -1, &compiledStatement, NULL);
if(prepareStatementResult == SQLITE_OK) {
// Check if the query is non-executable.
if (!queryExecutable){
// In this case data must be loaded from the database.
// Declare an array to keep the data for each fetched row.
NSMutableArray *arrDataRow;
// Loop through the results and add them to the results array row by row.
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Initialize the mutable array that will contain the data of a fetched row.
arrDataRow = [[NSMutableArray alloc] init];
// Get the total number of columns.
int totalColumns = sqlite3_column_count(compiledStatement);
// Go through all columns and fetch each column data.
for (int i=0; i<totalColumns; i++){
// Convert the column data to text (characters).
char *dbDataAsChars = (char *)sqlite3_column_text(compiledStatement, i);
// If there are contents in the currenct column (field) then add them to the current row array.
if (dbDataAsChars != NULL) {
// Convert the characters to string.
[arrDataRow addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
// Keep the current column name.
if (self.arrColumnNames.count != totalColumns) {
dbDataAsChars = (char *)sqlite3_column_name(compiledStatement, i);
[self.arrColumnNames addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
}
// Store each fetched data row in the results array, but first check if there is actually data.
if (arrDataRow.count > 0) {
[self.arrResults addObject:arrDataRow];
}
}
}
else {
// This is the case of an executable query (insert, update, ...).
// Execute the query.
BOOL executeQueryResults = sqlite3_step(compiledStatement);
if (executeQueryResults == true) {
// Keep the affected rows.
self.affectedRows = sqlite3_changes(sqlite3Database);
// Keep the last inserted row ID.
self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database);
}
else {
// If could not execute the query show the error message on the debugger.
NSLog(#"DB Error: %s", sqlite3_errmsg(sqlite3Database));
}
}
}
else {
// In the database cannot be opened then show the error message on the debugger.
NSLog(#"%s", sqlite3_errmsg(sqlite3Database));
}
// Release the compiled statement from memory.
sqlite3_finalize(compiledStatement);
}
// Close the database.
sqlite3_close(sqlite3Database);
}
Before accessing your database, have you copied it into document directory ?
Like this :
static sqlite3 *database = nil;
+ (void)openDatabase
{
[self copyDatabaseIfNeeded];
(sqlite3_open([[self getDBPath] UTF8String],&database));
}
+ (NSString *)getDBPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSLog(#"%#",documentsDir);
return [documentsDir stringByAppendingPathComponent:#"databaseName.sqlite"];
}
+ (void)copyDatabaseIfNeeded
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
NSLog(#"dbpath=%#",dbPath);
if(!success)
{
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"databaseName.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message \"%#\".", [error localizedDescription]);
}
}
Also check that the table which you are going to access is created in database before use.

implementing WAL in iOS?

The code I placed below works. So my scenario is I have the code below in a class. I use this class simply for merging tables and updating one table. When I call the object that this code lives in the app delegate for example, it works great! But when I call the same object after clicking a button in a tableview controller, I get a database lock error. So here's what I am wondering. After reading sqlite documentation WAL: http://www.sqlite.org/wal.html I am thinking that I cannot read and update concurrently to the sqlite db, right? I am unsure of a solution around this, so what would be a good suggestion around my problem. Remember, keep in mind this code works just fine in the app delegate, it does not work in my tableview controller when I call it using action upon clicking the button. Note: I SELECT data from the SQLITE database to display table cell names etc. Thanks ahead of time!
//Allocates a filemanager object. Ideally, this object is used for searching through the applications context
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL dbErr = NO;
//Boolean variable to tell if the database exists
BOOL error,mainDbError;
//Looks through all the databases. If there is a database that does not exist, the following error message will appear to the user. If all the databases exist on the system, the database opens respectively
error = [self checkAndOpenSyncDB];
mainDbError = [self checkAndOpenMainDB];
if (!error&&mainDbError) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Oops!"
message:#"We didn't mean for this to happen. Looks like there was a problem loading the sync database. Contact technical support for further assistance."
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
else{
//This is I think to check when the last time the sync occured on the system.. not quite sure though1
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSLog(#"Erorr syncing the database: Code: %d, message: '%s'", error,sqlite3_errmsg(syncOpenHandle));
char *errorMessage;
int errorNum = 0;
//Atataching the sync db to the master db
NSString *attachSQL = [NSString stringWithFormat:#"ATTACH DATABASE \'%#\' AS sync_db", self->pathForSync];
NSLog(#"PATH FOR SYNC !!!!!!! %#", pathForSync);
NSLog(#"Here's the arratch string: %#", attachSQL);
//
if (sqlite3_exec(syncOpenHandle, [attachSQL UTF8String], NULL, NULL, &errorMessage) == SQLITE_OK) {
NSString *masterQuery = [NSString stringWithFormat:#"SELECT name FROM sqlite_master WHERE type='table';"];
const char *masterStmt = [masterQuery UTF8String];
sqlite3_stmt *statement;
BOOL loopErr;
loopErr = sqlite3_prepare_v2(syncOpenHandle, masterStmt, -1, &statement, NULL);
if (sqlite3_prepare_v2(syncOpenHandle, masterStmt, -1, &statement, NULL)==SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSString * currentTable = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
NSLog(#"Here's the current table: %#",currentTable);
//This is where the magic happens. If there are any keys matching the database, it will update them. If there are no current keys in the database, the query will insert them.
if ([currentTable isEqualToString:#"USER_DATA"] == NO && [currentTable isEqualToString:#"USER_ACTIVITY"]== NO && [currentTable isEqualToString:#"USER_ITINERARY"] == NO) {
NSString *tblUpdate = [NSString stringWithFormat:#"INSERT or REPLACE INTO main.%# SELECT * FROM sync_db.%#;",currentTable, currentTable];
const char *updateStmt = [tblUpdate UTF8String];
//sqlite3_busy_timeout (mainOpenHandle, 60000);
bool update;
update = sqlite3_exec(syncOpenHandle, updateStmt, NULL, NULL, &errorMessage)== SQLITE_OK;
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
if (sqlite3_exec(syncOpenHandle, updateStmt, NULL, NULL, &errorMessage)== SQLITE_OK) {
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
if (errorNum == 1) {
//A database reset is needded
//self->isResetDataBase = YES;
}
dbErr = YES;
}
}
}
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
}
NSLog(#"Here's the error num %d", errorNum);
NSLog(#"Erorr syncing the database: Code: %d, message: '%s'", error,sqlite3_errmsg(syncOpenHandle));
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
sqlite3_finalize(statement);
//Detaching the database from the mainDB
NSString *detachSQL = [NSString stringWithFormat:#"DETACH DATABASE sync_db"]; // reference sync db
if ((errorNum = sqlite3_exec(syncOpenHandle, [detachSQL UTF8String], NULL, NULL, &errorMessage))!= SQLITE_OK) {
NSLog(#"Detatched syncDb Failed. ErrorMessage = %s ", errorMessage);
}
}
}
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
//Closing the database when finished.
if (syncOpenHandle!=nil) {
sqlite3_close(syncOpenHandle);
NSError *err;
int success = [fileManager fileExistsAtPath:pathForSync];
if (success) {
[[NSFileManager defaultManager]removeItemAtPath:pathForSync error:&err];
}
}

Rows not updating sqlite3

The following code is suppose to update 2 columns (HoursWorked and TotalEarned) in the row where Date(Primary Key) = todays date which is stored in the string dbDate. I think my update string might be written wrong. The alert view is being triggered.
sqlite3_stmt *newstatement;
sql =[NSString stringWithFormat:#"UPDATE HourLog SET HoursWorked = '%#', TotalEarned = '%#' WHERE Date ='%#'", HoursWorked, TotalEarned, dbDate];
if(sqlite3_prepare_v2(db, [sql UTF8String], -1, &newstatement, nil)==SQLITE_OK){
NSLog(#"details updated");
UIAlertView *alertDialog;
alertDialog = [[UIAlertView alloc]
initWithTitle:#"Title"
message:#"Details Updated!"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles: nil];
[alertDialog show];
sqlite3_step(newstatement);
}
sqlite3_finalize(newstatement);
sqlite3_close(db);
A couple of issues:
The UPDATE syntax is not correct. The individual fields being updated must be separated by a comma, not the word AND.
You probably shouldn't report that the update succeeded until you confirmed the result of sqlite3_step.
In case you're not getting a hit on your WHERE clause, I might suggest determining how many rows were updated, so you can confirm that the WHERE clause succeeded.
And, as always, report sqlite3_errmsg if your SQLite calls fail or else you're flying blind.
Thus:
sqlite3_stmt *statement;
int originalTotalCount = sqlite3_total_changes(db);
NSString *sql = [NSString stringWithFormat:#"UPDATE HourLog SET HoursWorked = %# , TotalEarned = %# WHERE Date='%#'", HoursWorked, TotalEarned, dbDate];
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil) != SQLITE_OK) {
NSLog(#"%s: prepare failed: %s", __FUNCTION__, sqlite3_errmsg(db));
} else {
if (sqlite3_step(statement) != SQLITE_DONE) {
NSLog(#"%s: step failed: %s", __FUNCTION__, sqlite3_errmsg(db));
} else {
int rowsUpdated = sqlite3_total_changes(db) - originalTotalCount;
NSString *message;
if (rowsUpdated == 1)
message = #"Updated one row";
else if (rowsUpdated == 0)
message = #"No rows updated";
else
message = [NSString stringWithFormat:#"Updated %d rows", rowsUpdated]; // should never happen
NSLog(#"%#", message);
UIAlertView *alertDialog = [[UIAlertView alloc] initWithTitle:nil
message:message
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil];
[alertDialog show];
}
sqlite3_finalize(statement);
}
I personally wouldn't use the single quotes around the numeric values for HoursWorked and TotalEarned. And you might consider storing the date in one of the established SQLite date formats.

sql and UIPickerView

I need to develop a sql statement based on values picked on a UIPickerView. If you need a visual idea, here's a link to the screenshot (sorry not enough reputation to post pics yet) . I haven't been able to find any documentation on this and want to make sure I'm on the right track before I dig into it.
Each component (kTypeComponent, kDifficultyComponent, kDescriptionComponent) has three rows to select from (ex. kTypeComponent row1=bike, row2=run, row3=swim)
My thought would be that the sql statement would look something like this
sqlite3_stmt *pickerStatement;
//This would give back a string of the row selected (i.e bike, run, swim)
NSInteger getTypeSelected = [pickerView selectedRowInComponent:kTypeComponent];
NSString typeSQL = [rowOneItems objectAtIndex:getTypeSelected];
const char *pickerSQL = "SELECT description FROM workoutTbl WHERE (type = typeSQL) AND ...
Is this possible to do with a sql statement? I'm only familiar with basic SQL, so I'm not sure
Would the SQL statement go in the action (button) or where I set up my NSMutableArray and open the database? Should it go into a different class?
Edit - Solution
In case anyone comes around with the same problem, here is the solution to it
- (NSArray *)getWorkoutListwithType:(NSString *)workoutType withDifficulty:(NSString *)difficulty withLength:(NSString *)length {
NSMutableArray *workouts;
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"workoutList.sqlite"];
// NSLog(#"Db path is %#",dbPath);
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if (!success){
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if (!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)) {
NSLog(#"error with message '%s'.", sqlite3_errmsg(db));
}
// only alloc/init the array if the SQL database opens properly
workouts = [[NSMutableArray alloc] init];
sqlite3_stmt *sqlStatement;
// add "%%" as a wildcard so the query will say "difficulty LIKE '>30%' and match >30 MINS, >30 HOURS, etc.
NSString *sqlString = [NSString stringWithFormat: #"SELECT description FROM workoutTbl WHERE type LIKE '%#%%' AND difficulty LIKE '%#%%' AND duration LIKE '%#%%'", workoutType, difficulty, length];
NSLog(#"query: %#", sqlString);
const char *sql = [sqlString UTF8String];
if (sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK) {
NSLog(#"%s Prepare failure '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(db), sqlite3_errcode(db));
}
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
[workouts addObject:[NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,0)]];
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}
#finally {
sqlite3_close(db);
}
// Pass back an immutable copy of the array. if the array is nil, then the database never opened and there will be an error
return [workouts copy];
}
What do you mean by 'three rows to select'? Do you mean 'three fields (columns) to select'? If you want to specify field values, then a statement should like
NSString* sqlStatement = [NSString stringWithFormat:#"SELECT * FROM workoutTbl WHERE type = '%#' AND id = '%i'", typeSQL,idNumber];

cannot insert value to sqlite DB iOS

Well following this tutorial I have some problems in inserting values to my DB although everything seems to be working fine.
This is my code for inserting entries.
-(void)insertOrder:(MyOrderList*)entry
{
// Create insert statement for the person
NSString *insertStatement = [NSString stringWithFormat:#"INSERT INTO LIST (URL, CODE, EMAIL, FULL) VALUES (\"%#\", \"%#\", \"%#\",\"%#\")", entry.db_url, entry.db_code, entry.db_email,entry.db_full];
NSLog(#"SQL INSERTION COMMAND:%#",insertStatement);
char *error;
if ( sqlite3_exec(databaseHandle, [insertStatement UTF8String], NULL, NULL, &error) == SQLITE_OK)
{
NSLog(#"Order inserted.");
}
else
{
NSLog(#"Error: %s", error);
}
}
And I can see "Order Inserted" being printed out.
This is my code for retrieving the list.
-(NSArray*) getList
{
NSMutableArray *persons = [[NSMutableArray alloc]init];
NSString *queryStatement = [NSString stringWithFormat:#"SELECT URL,CODE ,MAIL, FULL FROM LIST"];
sqlite3_stmt *statement;
NSLog(#"Query:%#",queryStatement);
if (sqlite3_prepare_v2(databaseHandle, [queryStatement UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
// Iterate over all returned rows
while (sqlite3_step(statement) == SQLITE_ROW) {
NSLog(#"Url of my List is:%#",[NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)]);
MyOrderList *person = [[MyOrderList alloc]initWithUrl:[NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)] andCode:[NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 1)] andEmail:[NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 2)] andFull:[NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 3)]];
[persons addObject:person];
// Release the person because the array takes ownership
//[person release];
}
sqlite3_finalize(statement);
}
//return [persons autorelease];
return persons;
}
and this is how I use it in my .m file
DataController *dataController = [[DataController alloc]init];
[dataController initDatabase];
//[dataController release];
MyOrderList *order = [[MyOrderList alloc] initWithUrl:url_2 andCode:keycode andEmail:mail andFull:full_2 ];
[dataController insertOrder:order];
//data has been added
NSMutableArray* persons = [dataController getList];
and I see that persons are 0.
From terminal I see this:
Admins-MacBook-Air:~ admin$ sqlite3 Users/admin/Library/Application\ Support/iPhone\ Simulator/5.1/Applications/1A70F53B-133E-46AE-833E-13F205EA96EA/Documents/sqlite.db
SQLite version 3.7.12 2012-04-03 19:43:07
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .schema
Error: unable to open database "Users/admin/Library/Application Support/iPhone Simulator/5.1/Applications/1A70F53B-133E-46AE-833E-13F205EA96EA/Documents/sqlite.db": unable to open database file
Admins-MacBook-Air:~ admin$
it's like my db is not even created.
this is my code for creating the DB.
-(void)initDatabase
{
// Create a string containing the full path to the sqlite.db inside the documents folder
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:#"sqlite.db"];
NSLog(#"Path is:%#",databasePath);
// Check to see if the database file already exists
bool databaseAlreadyExists = [[NSFileManager defaultManager] fileExistsAtPath:databasePath];
// Open the database and store the handle as a data member
if (sqlite3_open([databasePath UTF8String], &databaseHandle) == SQLITE_OK)
{
// Create the database if it doesn't yet exists in the file system
if (!databaseAlreadyExists)
{
// Create the PERSON table
const char *sqlStatement = "CREATE TABLE IF NOT EXISTS LIST (ID INTEGER PRIMARY KEY AUTOINCREMENT, URL TEXT, CODE TEXT, EMAIL TEXT, FULL TEXT)";
char *error;
if (sqlite3_exec(databaseHandle, sqlStatement, NULL, NULL, &error) == SQLITE_OK)
{
NSLog(#"Database and tables created.");
}
else
{
NSLog(#"Error: %s", error);
}
}
}
}

Resources