xcode sqlite delete row in one table where EXISTS in another table - objective-c

When I run the following code to delete a row from the MAIN.NOTES table, if tasks.todoDone does not have a match nothing is deleted in MAIN.NOTES. But if one tasks.todoDone is greater than '' then all the rows in MAIN.NOTES are deleted even if task.todoNod is not less than nod.
The second part of the code, deleting from MAIN.TASKS works correctly and only deletes rows that match both tests.
What do I have wrong in my EXISTS (select * line?
if (sqlite3_open(dbpath, &tasksDB) == SQLITE_OK) {
NSString *querySQLNotes = [NSString stringWithFormat:#"DELETE FROM MAIN.NOTES WHERE EXISTS (select * from MAIN.TASKS where tasks.todoNod <'%i' and tasks.todoDone > '')",nod];
char *errMsg;
const char *query_stmtN = [querySQLNotes UTF8String];// this should delete the notes for task that will be deleted next
if (sqlite3_exec(tasksDB, query_stmtN, NULL, NULL, &errMsg) == SQLITE_OK) {
int tc = sqlite3_changes(tasksDB);
NSLog(#"total count of deleted notes %i",tc);
}
NSString *querySQL = [NSString stringWithFormat:#"DELETE FROM MAIN.TASKS WHERE todoNod <'%i' and todoDone > ''",nod];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(tasksDB, query_stmt, -1, &statement, NULL) == SQLITE_OK) {
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(#"Match found and deleted");
} else {
NSLog(#"Match found and not deleted");
}
sqlite3_finalize(statement);
int tc = sqlite3_changes(tasksDB);
NSLog(#"total count of deleted tasks %i",tc);
}
sqlite3_close(tasksDB);
}
Thanks

Related

SQLite use UITextfield to select column header

This section of code works great. However, there is the opportunity to pick total of 3 of five search choices. With this in mind, I would like to use UITextFields for the WHERE. For example, replace "Chain = ?" replaced with "search.text = ?". I am familiar with "WHERE Chain=\"%#\"",_somthing.text" but can't work out how to replace the hard code column header with a UITextField.
Can any body please help?
NSString *querySQL = [NSString stringWithFormat:#"SELECT FullName FROM storeDetails WHERE (Chain = ? AND Format = ? AND RegionCode = ?)"];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(detailspapav2, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, [_choiceText1.text UTF8String], -1, NULL) != SQLITE_OK) {
NSLog(#"Bind 1 failed");
}
if (sqlite3_bind_text(statement, 2, [_choiceText2.text UTF8String], -1, NULL) != SQLITE_OK) {
NSLog(#"Bind 2 failed");
}
if (sqlite3_bind_text(statement, 3, [_choiceText3.text UTF8String], -1, NULL) != SQLITE_OK) {
NSLog(#"Bind 3 failed");
}
}
If you want the column name to be dynamic, change your querySQL line to something line:
NSString *querySQL = [NSString stringWithFormat:#"SELECT FullName FROM storeDetails WHERE (%# = ? AND Format = ? AND RegionCode = ?)", search.text];
However, this is dangerous. If search.text contains a value that doesn't exactly match the name of a column in your FullName table, the query will fail.

Get rows from a SELECT sql statement

I have a database, and i do a S ELECT statement on SQL for 10 random rows.
It's for Iphone App, so Objective C.
How could i get back the information after the statement ?
...
const char *sql3 = [[NSString stringWithFormat:#"SELECT id FROM tabledesquestions ORDER BY RANDOM() LIMIT 10"] cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *sql1Statement;
if(sqlite3_prepare(database1, sql3, -1, &sql1Statement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement");
}
while (sqlite3_step(sql1Statement)==SQLITE_ROW) {
numeroqdonnee = sqlite3_column_int(sql1Statement, 0);
}
For now, i get back info just for the first row. How could i get back the info (id) for the others rows.
I would like something like that
numeroqdonnee2 =
numeroqdonnee3 =
numeroqdonnee4 =
...
Many thanks
You could add the results to some array:
const char *sql3 = [[NSString stringWithFormat:#"SELECT id FROM tabledesquestions ORDER BY RANDOM() LIMIT 10"] cStringUsingEncoding:NSUTF8StringEncoding];
NSMutableArray *results = [NSMutableArray array];
sqlite3_stmt *sql1Statement;
int returnCode;
if(sqlite3_prepare(database1, sql3, -1, &sql1Statement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(database1));
}
else
{
while ((returnCode = sqlite3_step(sql1Statement)) == SQLITE_ROW) {
numeroqdonnee = sqlite3_column_int(sql1Statement, 0);
[results addObject:#(numeroqdonnee)];
}
if (returnCode != SQLITE_DONE)
NSLog(#"Problem with step statement: %s", sqlite3_errmsg(database1));
sqlite3_finalize(sql1Statement);
}
// now do whatever you want with this results array
NSLog(#"results = %#", results);
// or
[results enumerateObjectsUsingBlock:^(NSNumber *obj, NSUInteger idx, BOOL *stop) {
NSLog(#"numeroqdonnee%d = %d", idx, [obj integerValue]);
}];
Or you could just log the results directly:
const char *sql3 = [[NSString stringWithFormat:#"SELECT id FROM tabledesquestions ORDER BY RANDOM() LIMIT 10"] cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *sql1Statement;
int returnCode;
if(sqlite3_prepare(database1, sql3, -1, &sql1Statement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(database1));
}
else
{
while ((returnCode = sqlite3_step(sql1Statement)) == SQLITE_ROW) {
numeroqdonnee = sqlite3_column_int(sql1Statement, 0);
NSLog(#"numeroqdonnee = %d", numeroqdonnee);
}
if (returnCode != SQLITE_DONE)
NSLog(#"Problem with step statement: %s", sqlite3_errmsg(database1));
sqlite3_finalize(sql1Statement);
}
Note, I'd suggest you log the sqlite3_errmsg if you have any problems (otherwise you're just flying blind). I've also added the sqlite3_finalize (which your original code sample may have had, but I just wanted to make sure).

sqlite3_column_text returning Null

I have a table and I want to print the content of a row here is the table structure:
CREATE TABLE "quotes_type" ("type_id" INTEGER PRIMARY KEY NOT NULL , "content" TEXT)
I can see the type_id with debug and the value is correctly 1 but I can't return the context value with the help of sqlite3_column_text here is the code:
NSString *qry = [NSString stringWithFormat: #"select * from quotes_type"];
const char *count_stmt = [qry UTF8String];
sqlite3_prepare_v2(contactDB, count_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_ERROR) {
NSAssert1(0,#"Error when selecting rows %s",sqlite3_errmsg(contactDB));
} else {
int myid=sqlite3_column_int(statement, 0);
NSLog(#"Context: %s", sqlite3_column_text(statement, 1));
NSLog(#"myid is %d",myid);
sqlite3_finalize(statement);
sqlite3_close(contactDB);
the problem is this line:
NSLog(#"Data: %s", sqlite3_column_text(statement, 1));
the result is Null
I realized that it doesn't update my sqlite file and it is reading from my previous one how can I force it to read from the new one?even I deleted all .sqlite files but still it is reading it from somewhere

Whats wrong with my SQLITE3 insert method?

Very confused by this... my "DiscoveredCars" table begins with two records in it. The first time I call this method with it inserts properly and the last line displays "3" for the number of records.
Yet the second time I call it, the SQL looks perfect yet for some reason it still is showing "3" for the size and does not seem to be inserting properly? Any ideas?
- (void)writeToDiscoveredCars: (Car *)car {
NSString *tempSQL = [NSString stringWithFormat:#"INSERT INTO DiscoveredCars (car_ID) VALUES (%i)", car.ID];
NSLog(#"size of discoveredis %i", [self numberRecordsForTable:#"DiscoveredRecipes"]);
NSLog(#"SQL insert is %#", tempSQL);
const char *sql = [tempSQL UTF8String];
sqlite3_stmt *statement;
int sqlResult = sqlite3_prepare_v2(myDatabase, sql, -1, &statement, NULL);
if (sqlResult == SQLITE_OK) {
sqlResult = sqlite3_step(statement);
if(sqlResult == SQLITE_DONE)
{
}
sqlite3_finalize(statement);
}
else
{
NSLog(#"1. problem with database");
NSLog(#"%s", sqlite3_errmsg(myDatabase));
}
NSLog(#"size of discoveredis %i", [self numberRecordsForTable:#"DiscoveredCars"]);
}
You never execute your query by calling sqlite3_step.
int sqlResult = sqlite3_prepare_v2(myDatabase, sql, -1, &statement, NULL);
if (sqlResult == SQLITE_OK) {
sqlResult = sqlite3_step(statement); //Execute!
//check the result for completion
if(sqlResult == SQLITE_DONE)
{
}
sqlite3_finalize(statement);
}

Count Number of Rows in a SQLite Database

I'm trying the following code to count the number of rows in my SQLite database table, but it throws an exception. Is these a simpler way to do this?
- (void) countRecords {
int rows = 0;
#try {
NSString *dbPath = [self getDBPath];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
NSString *strSQL;
strSQL = #"SELECT COUNT(*) FROM MYTABLE";
const char *sql = (const char *) [strSQL UTF8String];
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) == SQLITE_OK) {
// THIS IS WHERE IT FAILS:
if (SQLITE_DONE!=sqlite3_step(stmt) ) {
NSAssert1(0,#"Error when counting rows %s",sqlite3_errmsg(database));
} else {
rows = sqlite3_column_int(stmt, 0);
NSLog(#"SQLite Rows: %i", rows);
}
sqlite3_finalize(stmt);
}
sqlite3_close(database);
}
}
#catch (NSException * e) {
NSLog(#"Error Counting");
}
}
I came across a solution, using my code above, just replacing the step statement with the code below:
if (sqlite3_step(stmt) == SQLITE_ERROR) {
NSAssert1(0,#"Error when counting rows  %s",sqlite3_errmsg(database));
} else {
rows = sqlite3_column_int(stmt, 0);
NSLog(#"SQLite Rows: %i", rows);
}
This usually works for me
- (NSInteger )numberRecordsForTable:(NSString *)table {
NSInteger numTableRecords = -1;
if (sqlite3_open([self.dbPath UTF8String], &database) == SQLITE_OK) {
NSString *sqlStatement = [NSString stringWithFormat: #"select count(*) from %#", table];
const char *sql = [sqlStatement cStringUsingEncoding:NSUTF8StringEncoding];
if(sqlite3_prepare_v2(database, sql, -1, &sqlClause, NULL) == SQLITE_OK) {
while(sqlite3_step(sqlClause) == SQLITE_ROW) {
numTableRecords = sqlite3_column_int(sqlClause, 0);
}
}
else {
printf("could not prepare statement: %s\n", sqlite3_errmsg(database));
}
}
else {
NSLog(#"Error in Opening Database File");
}
sqlite3_close(database);
return numTableRecords;
}
HTH
There is no SQL expression to count rows in a database: you can count rows in a every table and then add them up.
I thought I'd trow in my two cents here as there is an expression to count rows in a database, I use it when dealing with MySQL databases using php scripts all the time. and I tested it in an ios app it's available in there too behold:
sqlite3 *database;
if(sqlite3_open([dbpath UTF8String], &database) == SQLITE_OK)
{
NSString *sql = #"select count(*) from today";
sqlite3_stmt *selectStatement;
int returnValue = sqlite3_prepare_v2(database, [sql UTF8String], -1, &selectStatement, NULL);
if (returnValue == SQLITE_OK)
{
if(sqlite3_step(selectStatement) == SQLITE_ROW)
{
numrows= sqlite3_column_int(selectStatement, 0);
}
}
sqlite3_finalize(selectStatement);
sqlite3_close(database);
}
no need for a fancy loop counter thing. btw if your using an auto increment int for the primary key. it works just slightly different then an array's key. where as in an array that is n items long the valid array elements are from 0 to n-1 in a database the key field is from 1 to n simple enough to work around if you just keep that in mind.
-(void)databaseRecordCount{
int rows = 0;
#try {
sqlite3 *database;
NSString *filePath = [self databaseDocumentsFilePath];
if(sqlite3_open([filePath UTF8String], &database) == SQLITE_OK) {
NSString *query = #"SELECT * FROM MYTABLE";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &compiledStatement, NULL) != SQLITE_OK)
NSLog(#"Error while creating detail view statement. '%s'", sqlite3_errmsg(database));
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &compiledStatement, nil) == SQLITE_OK) {
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
rows++;
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
}
#catch (NSException * e) {
NSLog(#"Error Counting");
}
NSLog(#"SQLite Rows: %i", rows);
NSUserDefaults *userDefaults;
userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setInteger:rows forKey:#"databaseRecordCount"];
[userDefaults synchronize];
}
You'll have to count of each table individually. Some pseudo code:
sql = "SELECT name FROM sqlite_master" WHERE type = 'table'
tables() = GetRows(sql)
Dim total As Integer
For Each t As String in tables
sql = "SELECT COUNT(*) FROM " + t
total = total + GetValue(sql)
Next
Show(total)