I'm trying to use the SQLite C API in my iPhone app. I'm trying to query an SQLite database for the number of records that have been completed after a certain date. The database saves the completed date as text in YYYY-MM-dd format. For example the text 2009-04-10 might appear as a completed date.
When I query the database from the commandline my query works, but when run from the app, it doesn't. Here's what I'm doing:
From the commandline, I run this query:
sqlite> SELECT COUNT(*) FROM tasks WHERE completed > '2009-04-09'
...> go
1
As you can see, there is one record found as I expect.
In my app, I execute this code (written in Objective-C, obviously):
static sqlite3_stmt *count_tasks_statement = nil;
if(count_tasks_statement == nil) {
const char *sql = "SELECT COUNT(*) FROM tasks WHERE completed > '?'";
if (sqlite3_prepare_v2(database, sql, -1, &count_tasks_statement, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
}
NSString *today = #"2009-04-09";
sqlite3_bind_text(count_tasks_statement, 1, [today UTF8String], -1, SQLITE_TRANSIENT);
// Get the row count from the query
NSInteger taskCount = 0;
if(sqlite3_step(count_tasks_statement) == SQLITE_ROW) {
// The second parameter indicates the column index into the result set.
taskCount = sqlite3_column_int(count_tasks_statement, 0);
}
// Reset the statement for future reuse.
sqlite3_reset(count_tasks_statement);
When I use the debugger on this code, and examine the taskCount variable, it is set to 0, indicating that no records were found. (If I change the code to return primary keys for found rows, it still returns nothing.)
Since it works from the commandline, but doesn't in my code, I assume that I'm doing something wrong with either the quoting of the question mark in my SQL, or with the binding of the literal text date to the query. But, I've tried it lots of different ways with no luck. Help!
Don't put parameter placeholders inside quotes, even if the value is a string or date literal.
const char *sql = "SELECT COUNT(*) FROM tasks WHERE completed > ?";
I think that you do not need the extra quotes around the question mark.
Try
const char *sql = "SELECT COUNT(*) FROM tasks WHERE completed > ?";
and it should work.
Related
Please can anyone tell me why we write NULL in the fifth parameter below?
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK)
Thanks in advance.
As long as your sql has only one statement, you don't need to use the fifth parameter. When sql has more than one statement, you can receive a pointer to the beginning of the next statement.
For example:
const char* sql =
"DROP TABLE price_list;"
"CREATE TABLE price_list ( item TEXT, price INTEGER)";
while ( *sql ) {
sqlite3_stmt* statement;
sqlite3_prepare_v2(db, sql, -1, &statement, &sql);
sqlite_step(statement);
sqlite_finalize(statement);
}
Because you don't care about the uncompiled part of the SQL statement. From the docs:
If pzTail is not NULL then *pzTail is made to point to the first byte past the end of the first SQL statement in zSql. These routines only compile the first statement in zSql, so *pzTail is left pointing to what remains uncompiled.
It's useful to have this if you have a string with many SQL statements, but if you don't then it's just cruft.
I am doing an iPad project, there are 3 tables in UI. if i select row in each table. Sqlite query will take the value from table and run the query. please find my Query below.
NSString * str3=tableFou.string4;
NSString * str4=tableFiv.string5;
NSString * str2=tablethr.string3;
sqlite3 *database;
favorite=[[NSMutableArray alloc]init];
if(sqlite3_open([databasePath UTF8String], &database)== SQLITE_OK){
NSString *sql=[NSString stringWithFormat:#"Create view prizeview as SELECT country.name,item_country.id,text.text,substr(text,1,2) FROM country,item_country,prize,item_prize,gender,item_gender,text WHERE country.name = '%#' AND text.item = item_country.item AND country.id = item_country.id AND prize.name = '%#' and text.item=item_prize.item and prize.id = item_prize.id and gender.name = '%#' and text.item=item_gender.item and gender.id = item_gender.id ",str3,str4,str2];
const char *sqlStatement = [sql UTF8String];;
problem is that, the query is running if i select all the tables only.. but i want results if i select even one table. how can i do that?
Try with if condition use with and condition and pass all your str in if condition only.
use your if condition like this.
if(([propertyTypeLabel.text length]==0) || ([cityLabel.text length]==0 ) ||( [locationLabel.text length]==0 )|| ([priceLabel.text length] ==0)||([postedLabel.text length]==0))
In this like any of text is zero condition true you also use if ant of the table cell is tap your query run.
You can't search for empty fields unless the field is actually empty. F.ex. if you search
select * from mytable where username = "";
You won't find it, but if you are ok with the field being empty or whatever result, you must use like instead of =
select * from mytable where username like "%";
or better yet, you can create your query like this, lets say you have three fields to search for, username, firstname and lastname. The code below needs a few more if's and buts, but you should be able to make this work and only add the parameters to where if they fulfill the requirements.
NSMutableString *query = [[NSMutableString alloc] init];
[query appendString:#"select * from table where "];
if (username.text.lenghth >1) [query appendString:[NSString stringWithFormat:#"username = '%#'"]];
if (firstname.text.length >1) [query appendString:[NSString stringWithFormat:#"&& firstname = '%#'"]];
if (lastname.text.length >1) [query appendString:[NSString stringWithFormat:#"&& lastname = '%#'"]];
Hope this helps
I am trying to delete some entries in my sqlite database on my iPhone app, but am getting a weird error.
Here is my code:
if(sqlite3_open([databasePath UTF8String], &yerocDB)==SQLITE_OK)
{
sqlite3_stmt *compiledstatement;
NSString *deleteSql=[NSString stringWithFormat: #"delete from Favorites_Table where playlist_name = Studying and date = 1/1/2012"];
const char *sqlstmt = [deleteSql UTF8String];
if(sqlite3_prepare_v2(yerocDB, sqlstmt, -1, &compiledstatement, NULL)==SQLITE_OK)
{
int result = sqlite3_step(compiledstatement);
if(SQLITE_DONE != result)
NSAssert1(0,#"Error while creating delete statement => %s",sqlite3_errmsg(yerocDB) );
}else{
NSLog(#"didn't delete error: %s", sqlite3_errmsg(yerocDB));
}
sqlite3_finalize(compiledstatement);
}
but then I get the error:
didn't delete error: no such column: Studying
playlist_name and date are my columns...Why is it saying the "Studying" is not a column?
You need to wrap Studying in single quotes. And your date.
This:
delete from Favorites_Table
where playlist_name = Studying and date = 1/1/2012
Should be this:
delete from Favorites_Table
where playlist_name = 'Studying' and date = '2012-01-01'
The reason is that if you don't put it in single quotes, the parser will think it's a column name. In your first query, you were trying to delete from Favorites_Table where the playlist_name column equalled the Studying column. Henceforth your error, "No such column."
And once you fixed the quotes around studying, your date was going to throw an error, too. Dates use ISO format (yyyy-mm-dd) to compare. Don't use the localized mm/dd/yyyy or dd/mm/yyyy formats, as a rule of thumb.
Is there a way to see what the resulting 'showStatement' is after sqlite3_prepare_v2 and sqlite3_bind_xxx ?
Running this query :
SELECT *
FROM shows, locations
WHERE (shows.day_id = 1)
AND (shows.id IN (6,7,15,19,23,66))
AND (shows.location_id = locations.id)
ORDER by locations.sort_order
runs perfectly in SQLite Manager and in code when I enter it EXACTLY like that. If I however do parameter substitution the query returns no results...
if (sqlite3_open([databasePath UTF8String],&showsDatabase) == SQLITE_OK){
const char *sqlStatement = "SELECT * FROM shows, locations WHERE (shows.day_id = ?) AND (shows.id IN (?)) AND (shows.location_id = locations.id) ORDER by locations.sort_order";
sqlite3_stmt *showStatement;
if(sqlite3_prepare_v2(showsDatabase, sqlStatement, -1, &showStatement, NULL) == SQLITE_OK) {
sqlite3_bind_int(showStatement, 1, forDay);
sqlite3_bind_text(showStatement, 2, allFavorites,-1,NULL);
int error = sqlite3_step(showStatement);
while(sqlite3_step(showStatement) == SQLITE_ROW) {
...
The problem must lie in the IN (6,7...) part, without that it works perfect.
My debugger shows me that forDay = 1 and that allFavorites = 6,7,15,19,23,66
but the error = 101 = sqlite3_step() has finished executing = no lines found
Being able to see the 'showStatement' variable in one way or another would solve the problem, however the debugger doesn't give that info
You can't bind IN (?) with an array.
You need to write shows.id IN (?, ?, ?, ?, ?, ?) and bind each parameter separately. The number of question marks also has to match the number of parameters so you might need to construct the query dynamically if the number can vary.
i want to update my sqlite database but i cannot find the way to do it,following is the code:
const char *sqlStatement = "UPDATE frame SET fileExist = '1' WHERE name='$variable'";
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
NSLog(#"successupdate");
}
from the above code i want my table update where the name is equal to $variable name;how to achieve this?
You're nearly there.
const char *sqlStatement = "UPDATE frame SET fileExist = '1' WHERE name=?";
sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL);
sqlite3_bind_text(sqlStatement, 1, variable, -1, SQLITE_TRANSIENT);
int success = sqlite3_step(sqlStatement);
sqlite3_reset(sqlStatement);
Note that preparing the SQL statement only tells SQLite what the statement looks like. It's sqlite3_bind_text that applies the variable to the SQL statement and the sqlite3_step line that actually runs it.
FMDB is a nice wrapper for SQLite statements. It takes care of most of the prepare/bind/step/reset drudgery. I highly recommend it for any project that needs a DB, but doesn't want to use Core Data.