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];
Related
I am running SQLite query on my database. The select query is working fine, but when I am running SQLite query no error is generated, but it is still not updating my database values.
The function is as follows :
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"bikeapp.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured.");
}
NSString *query = [NSString stringWithFormat:#"UPDATE bikes SET to_show = 0 where id = %ld",(long)bikeId];
//const char *sql = "UPDATE bikes SET to_show = 0 where id = 3";
const char *sql = [query UTF8String];
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement");
}
if(sqlite3_step(sqlStatement))
{
return YES;
}else
return NO;
//
}
#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}
The code runs through without any error or exception but it is not updating the values inside the database. The query when run directly on database shows the changes being done. If anybody can help me out here I would appreciate it. Thanks.
I have an sqlite database which has a 6000 rows in it. I need to import the text from it .It successfully imports the text but takes lot of time . I dont need to import all the rows at a time , It should display the 100-300 rows in UITextView when i clicked each cell in UITableView . the code Iam using is as follows :
#try
{
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"MyDatabase.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured.");
}
const char *sql = "SELECT ID, MyText FROM MyTable ";
if(sqlite3_prepare_v2(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement");
}
string = [[NSMutableString alloc]init];
MyTextView.text=#"";
while (sqlite3_step(sqlStatement)==SQLITE_ROW)
{
DetailsIDs *MyDetails = [[DetailsIDs alloc]init];
MyDetails.MyText = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 2)];
[MyTextView setText:[NSString stringWithFormat:#"%# \n%#", MyTextView.text,MyDetails.MyText]];
}
}
#catch (NSException *exception)
{
NSLog(#"An mmmm exception occured: %#", [exception reason]);
}
#finally
{
}
}
I need a fastest way to retrive the text from database,
Iam stuck ! plz help me , Thanks !
Here is your performance problem:
[MyTextView setText:[NSString stringWithFormat:#"%# \n%#", MyTextView.text,MyDetails.MyText]];
You should probably use an NSMutableString and append to it, if you really want everything in one long string like that.
I'm trying to get data from my DB but I have some problem.
Here is my code:
NSString *action=[[NSString alloc]init];
NSString *queryStatement = [NSString stringWithFormat:#"SELECT ACTIONNAME FROM ACTIONS WHERE ACTIONSYMBOL = '%#'", symbol];
// Prepare the query for execution
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [queryStatement UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
// Create a new address from the found row
while (sqlite3_step(statement) == SQLITE_ROW) {
action = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 1)]; // fails on this line
}
sqlite3_finalize(statement);
return action;
}
(the parameter symbol come from outside)
When I run this, it fails at the line with the call to stringWithUTF8String with sqlite3_column_text results.
You probably want to collect the results in an NSMutableArray:
NSMutableArray *action = [[NSMutableArray alloc] init];
...
while (sqlite3_step(statement) == SQLITE_ROW) {
[action addObject:[NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)]];
}
...
You can then see what was collected later:
for (NSString *s in action) {
NSLog(#"%#", s);
}
EDIT As pointed out in #Rob's answer, the first column is 0, not 1.
In your call to sqlite3_column_text, you're using the index 1, but it takes a zero-based index. Use 0 instead of 1. See the SQLite sqlite_column_XXX documentation, which says:
The leftmost column of the result set has the index 0.
By the way, since stringWithUTF8String throws an exception if you pass it a NULL value, it's often safer to check the result if sqlite3_column_text is not NULL before proceeding, and handle the error gracefully otherwise. Also, you might want to check for sqlite3_step and sqlite3_prepare_v2 errors, like so:
NSString *queryStatement = [NSString stringWithFormat:#"SELECT ACTIONNAME FROM ACTIONS WHERE ACTIONSYMBOL = '%#'", symbol]; // note, it can be dangerous to use `stringWithFormat` to build SQL; better to use `?` placeholders in your SQL and then use `sqlite3_bind_text` to bind the `symbol` value with the `?` placeholder
if (sqlite3_prepare_v2(database, [queryStatement UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
int rc;
while ((rc = sqlite3_step(statement)) == SQLITE_ROW) {
const unsigned char *value = sqlite3_column_text(statement, 0); // use zero
if (value) {
NSString *action = [NSString stringWithUTF8String:(const char *)value];
// now do whatever you want with `action`, e.g. add it to an array or what
} else {
// handle the error (or NULL value) gracefully here
}
// make sure to check for errors in `sqlite3_step`
if (rc != SQLITE_DONE)
{
NSLog(#"%s: sqlite3_step failed: %s", __FUNCTION__, sqlite3_errmsg(database));
}
}
}
else
{
NSLog(#"%s: sqlite3_prepare_v2 failed: %s", __FUNCTION__, sqlite3_errmsg(database));
}
Incidentally, as the above illustrates, to correctly perform all of the error checking is a little cumbersome. This is where FMDB can be useful, simplifying the above to (where db is an FMDatabase object that has been opened):
FMResultSet *rs = [db executeQuery:#"SELECT ACTIONNAME FROM ACTIONS WHERE ACTIONSYMBOL = ?", symbol];
if (!rs) {
NSLog(#"%s: executeQuery failed: %#", __FUNCTION__, [db lastErrorMessage]);
return;
}
while ([rs next]) {
NSString *action = [rs stringForColumnIndex:0];
// do whatever you want with `action` here
}
[rs close];
And if you use ? placeholders (rather than using stringWithFormat to build your SQL, which is dangerous) the benefits of using FMDB are even more compelling.
Below is my code, I'm attempting to retrieve data from an sqlite database with airport city names query from a user entered text field and retrieve the ICAO identifier to be presented in a label. It seems the db is loading but it will not query when I select the IBAction button. I think there might be something wrong with my query statement or my database, although I can't list that on here. Any Help would be greatly appreciated.
The Last error I received is: database3[30351:c07] -[ViewController searchICAO:] 1st SQL error 'library routine called out of sequence' (21)
-(NSString*)filePath {
NSArray*paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[paths objectAtIndex:0]stringByAppendingPathComponent:#"mydatabase.sqlite"];
}
//open database
- (void)viewDidLoad{
[self openDB];
}
-(void)openDB {
if(sqlite3_open([[self filePath]UTF8String], &airportDB) !=SQLITE_OK) {
sqlite3_close(airportDB);
NSAssert(0, #"Databese failed to open");
status.text = #"Database Failed to Open";
}
else if (sqlite3_open([[self filePath]UTF8String], &airportDB) ==SQLITE_OK) {//this line not really needed but was trying everything
NSLog(#"database opened"); //test
status.text = #"Database Opened"; //test
}
}
- (IBAction)searchICAO:(id)sender
{
//[self.delegate detailViewControllerDidFinish:self]; //for later use
//Get airport name from the text field user enters
NSString*sql = [NSString stringWithFormat:#"SELECT * FROM airports WHERE city=\"%#\"", [searchDB text]];
const char *query_stmt = [sql UTF8String];
sqlite3_stmt *statement;
NSLog(#"%s 1st SQL error '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(airportDB), sqlite3_errcode(airportDB)); //Error Test
This is where I seem to be having problems at...
if (sqlite3_prepare_v2(airportDB, query_stmt, -1, &statement, NULL)==SQLITE_OK) {// Problem is from here, can't get past this point
NSLog(#"%s 2nd SQL error '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(airportDB), sqlite3_errcode(airportDB)); //Error Test
if (sqlite3_step(statement)==SQLITE_ROW) {
status.text = #""; //Clear the status line
NSString *returnICAO = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];
status.text = returnICAO; //Insert Airport ICAO letters from the database table
}
sqlite3_finalize(statement);
[super viewDidLoad];
}
sqlite3_close(airportDB);
}
I am not seeing exactly what is going wrong, but I would offer that, unless you have a specific objective that cannot be met by using third-party code, you should consider using FMDB https://github.com/ccgus/fmdb - assuming that you need to go directly to SQLite. I have used it quite a bit and had good success with it.
It's a little strange to be "closing" the DB and calling [super viewDidLoad] from searchICAO:. Was this deliberate? It seems like this might be the source of your problem? On the second query, the DB will be closed?
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);
}
}
}
}