How to update an entry in sqlite3? - ios

Im super new to ios (Objective-C) and sql and Im following a tutorial of sqlite (specifically sqlite3) found here: http://www.tutorialspoint.com/ios/ios_sqlite_database.htm
and i implemented everything correctly. The problem is that if I try to enter information with the same reg id (The primary key which is used to find elements in the database), it complains about the key not being unique.
- (BOOL) saveData:(NSString*)registerNumber name:(NSString*)name
department:(NSString*)department year:(NSString*)year;
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *insertSQL =
[NSString stringWithFormat:#"insert into studentsDetail (regno,name, department, year) values (\"%d\",\"%#\", \"%#\", \"%#\")",[registerNumber integerValue], name, department, year];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
int s = sqlite3_step(statement);
const char *errmsg = sqlite3_errmsg(database);
if (s == SQLITE_DONE)
{
sqlite3_reset(statement);
return YES;
}
else {
sqlite3_reset(statement);
return NO;
}
}
return NO;
}
How do I go about making the saveData: action actually update the entry inside the database instead of just being rejected?
Thanks!

"I want to extend it so that if I try to enter an existing reg id, it
will overwrite the remaining properties with the new ones"
If this is what you are trying to accomplish then you should not be using an INSERT statement. The purpose of the primary key is to protect the database from duplicate rows with the same primary key. When you look at it that way, the rejection is appropriate.
What you really want is to use INSERT OR REPLACE
If you're a beginner to both sql and objective c, I'd recommend a sqlite wrapper I created that is aimed at beginners: TankDB
Edit:
Code example:
INSERT OR REPLACE INTO studentsDetail (regno,name, department, year) values (\"%d\",\"%#\", \"%#\", \"%#\")"
Refer to this question to make sure that you don't actually mean to use 'UPSERT'. Beware that INSERT OR REPLACE does not update the existing row with the new information. It will completely delete the existing row and replace it.
Edit2: Open, prepare, step, finalize, close
const char *dbpath = [_databasePath UTF8String];
if(sqlite3_open(dbpath, &_database) == SQLITE_OK) {
const char *command = [query UTF8String];
// Perform the query
if (sqlite3_prepare_v2(_database, command, -1, &selectstmt, NULL) == SQLITE_OK) {
// For each row returned
while (sqlite3_step(selectstmt) == SQLITE_ROW) {
// Do stuff
}
}
sqlite3_finalize(selectstmt);
}
sqlite3_close (_database);

Related

How to execute two insert query in single statement in sqlite3 [duplicate]

This question already has an answer here:
Delete multiple tables from a single query by separating from semicolon
(1 answer)
Closed 7 years ago.
I am trying to insert the values in two different tables in a single statement, first insert query in working second query is not working.
sqlite3_stmt * statement= NULL;
const char *dbpath =[databasePath UTF8String];
if (sqlite3_open(dbpath, &mySqliteDB)== SQLITE_OK)
{
for (PostObject * post in in_PostObject)
{
**query**
NSString * postSql =[NSString stringWithFormat:#"insert or ignore into %#_post (postid,data,active) values (\"%#\",?,\"%d\");",tblPrefix,post.post_ID,post.active];
/*Appending First query with second query*/
NSString * insertSQl =[postSql stringByAppendingString:[NSString stringWithFormat:#" insert into %#_forumuser (uid,utype,name) values (1,'parent','javid');",tblPrefix]];
NSLog(#"%#",insertSQl);
const char * insert_stmt=[insertSQl UTF8String];
sqlite3_prepare_v2(mySqliteDB, insert_stmt, -1, &statement, NULL);
sqlite3_bind_text(statement, 1, [post.jsonData UTF8String], -1, SQLITE_TRANSIENT);
if (sqlite3_step(statement)==SQLITE_DONE)
{
success =TRUE;
}
else
{
NSLog(#"DB Error: %s", sqlite3_errmsg(mySqliteDB));
}
}
}
sqlite3_finalize(statement);
sqlite3_close(mySqliteDB);
You need to check the return code from the sqlite3_prepare_v2 to make sure there aren't any problems.
Also you shouldn't need to open and close the database for each statement you want to execute, there you could process them as 2 statements
if(sqlite3_prepare_v2(mySqliteDB, insert_stmt,-1, &statement, NULL) != SQLITE_OK) {
NSLog(#"%s Prepare failure '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(db), sqlite3_errcode(db));
}

Drop table sqlite issue

I've been able to drop and reload tables using this same code structure, but running into an issue for this table. Essentially what my code intends to do is allow the user to delete their custom selections and restore defaults. Any insight on why I'm unable to drop table is appreciated.
EDIT: the issue was that the inital table to drop did not exist. I ended up using sqlite3_errmsg to figure that out.
- (void) dropReloadFoodlistTable{
const char *dbpath = [_databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &_profileDB) == SQLITE_OK)
{
NSString *querySQL = #"DROP TABLE FOODLIST";
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(_profileDB,
query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"SQL Statement complete");
}
sqlite3_finalize(statement);
}
char *errMsg2;
const char *sql_stmt2 =
"CREATE TABLE IF NOT EXISTS FOODLIST (ID INTEGER PRIMARY KEY AUTOINCREMENT, CARB STRING, PROTEIN STRING, FAT STRING, FRUIT STRING, VEG STRING)";
if (sqlite3_exec(_profileDB, sql_stmt2, NULL, NULL, &errMsg2) != SQLITE_OK)
{
NSLog( #"Failed to create FOODLIST table");
}
sqlite3_close(_profileDB);
}
[self initialDataLoadFoodList];
}
This code does not execute the DROP TABLE statement.
To execute a prepared statement, you must call sqlite3_step.
You prepare the statement, but never use sqlite3_step() to actually execute it.
(reference)

SQLite update column if another column exists

Okay, so I'm not sure exactly how to name this question but I can explain what my issue is. I'm creating a webbrowser, and using an sqlite database to store the history. When the page finished loading my method:
-(void)addHistory:(NSString*)title address:(NSString*)url{
sqlite3_stmt *statement;
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_historyDB) == SQLITE_OK)
{
NSString *updateSQL = [NSString stringWithFormat:
#"UPDATE HISTORY SET title='%#' WHERE url='%#'", title, url];
const char *update_stmt = [updateSQL UTF8String];
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(_historyDB, update_stmt, -1, &stmt, NULL)==SQLITE_OK) {
NSLog(#"Updated");
}else{
NSString *insertSQL =
[NSString stringWithFormat:
#"INSERT INTO HISTORY (title, url, visits, date, search) VALUES (\"%#\", \"%#\", \"%#\", \"%#\", \"%#\")",
title, url, #"todo", #"todo", [NSString stringWithFormat:#"%# %#", title, url]];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(_historyDB, insert_stmt,
-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
NSLog(#"Added Entry");
} else {
NSLog(#"Coundn't Add Entry");
}
sqlite3_finalize(statement);
}
sqlite3_close(_historyDB);
}
}
I assumed that if the update failed (because the url is not present in the table) it would move to the else statement and add the key. The main idea behind this is to update the title of the webpage, and once that is working, update other fields such as last visited, amount of times viewed and so on..
I've experimented with a variety of different methods but I just can't seem to achieve the desired results.
To execute the update statement, you must call sqlite3_step for that statement.
To find out how many records were updated, call sqlite3_changes.
And you must handle any errors returned by the sqlite3_prepare_v2 calls.
And you must call sqlite3_finalize for stmt.
And any website with ' in its URL or title will corrupt your SQL statements; to avoid SQL injection attacks, use parameters.
I ended up making the switch to FMDB, a brilliant Objective-C wrapper for SQLite. I then performed a SELECTstatement where the url matched the current one, if it returned a value I updated the database, if not, I simply added to it.

sqlite query with multiple condition giving error : library routine called out of sequence

I am creating an app and using sqlite 3 for storing data.
Here is my code I am executing to fetch data
sqlite3_stmt *statement;
NSString *querySQL = [NSString stringWithFormat: #"SELECT ID, HolderName, AccountNumber, BankName, Location FROM Accounts WHERE UserID='%#'",userID];
if(![name isEqualToString:#""])
{
querySQL = [NSString stringWithFormat: #"SELECT ID, HolderName, AccountNumber, BankName, Location FROM Accounts WHERE UserID='%#' and HolderName='%#'",userID, name];
}
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(db, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
....
}
}
What is happening here, if name is empty then query(only with one condition in where clause) runs properly and fetches proper data but its giving error : library routine called out of sequence if name is not empty and query contains two conditions in where clause.
I am not sure what is wrong with it, I have searched a lot but found that query runs perfect with multiple conditions.
Please suggest me what should I do here.

Not able to update the column value in the sqlite3

I am new to the iPhone programming and was hoping that someone would be able to help me out with a problem that I've been trying to fix for a few days now. I have created a database and a table. In my program, it contain 5 fields and I am setting two of the fields to zero. And later I am updating these fields to one for a purpose. But the problem is I am not able to set the field value to one. I will paste the code below :
NSString *querySQL = [NSString stringWithFormat: #"UPDATE TODOLIST_03 SET DELETEROW ='1' WHERE TASK=\"%#\"", cellText1];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(TODOLIST_03_DB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
.........
}
}
Can anyone please tell me what is the error in the query?
try following :
const char *sqlQuery="UPDATE TODOLIST_03 SET DELETEROW ='1' WHERE TASK= ?";
if(sqlite3_prepare_v2(database, sqlQuery,-1, &queryStatement, NULL) == SQLITE_OK)
{
sqlite3_bind_text(queryStatement, 1, [cellText UTF8String], -1, NULL);
}
What path did you put database file at? It can not be wrote if you put the database file at the path same as project, you should put it in the sandbox for example NSHomeDocument where it is writeable, and you can modify code like this to track the error:
NSError *err;
if (sqlite3_prepare_v2(TODOLIST_03_DB, query_stmt, -1, &statement, &err) == SQLITE_OK)
{
if(err)
{
// NSLog error or what.
}
}

Resources