Reading from SQLite - FMDB - Beginner - iphone

I am trying to read from a database file (performing a simple select all functions).
I am using FMDB.
Here's how i created the DB;
Pro:~ dd$ sqlite3 db.db
SQLite version 3.7.7 2011-06-25 16:35:41
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table cus(id integer primary key, firstname varchar(30));
sqlite> inser into cus(firstname)values('f');
Error: near "inser": syntax error
sqlite> insert into cus(firstname)values('f');
sqlite> select * from cus;
1|f
sqlite>
I copied the file (db.db) to my resource folder in xCode. changed the name of the db file to db.db in the app delegate. Code for my program is exactly yhe same as this tutorial.
Here's the code ;
-(NSMutableArray *) getCustomers
{
NSMutableArray *customers = [[NSMutableArray alloc] init];
NSString * path = [(AppDelegate*)[[UIApplication sharedApplication]delegate]databasePath];
NSLog(#"DB path %# ",path);
FMDatabase *db = [FMDatabase databaseWithPath:path];
[db open];
FMResultSet *results = [db executeQuery:#"SELECT * FROM cus"];
NSLog(#"result %# ",results);
while([results next])
{
NSLog(#"result %# ",results);
Customer *customer = [[Customer alloc] init];
customer.customerId = [results intForColumn:#"id"];
customer.firstName = [results stringForColumn:#"firstname"];
[customers addObject:customer];
}
[db close];
return customers;
}
My problem;
Eventhough there is 1 record in the DB, the result of the Select statement is NULL. Why is this and how can i correct it ?

Assuming that the database was created and imported into the project successfully, try the following:
-(NSMutableArray *) getCustomers
{
NSMutableArray *customers = [[NSMutableArray alloc] init];
NSString * path = [(AppDelegate*)[[UIApplication sharedApplication]delegate]databasePath];
NSLog(#"DB path %# ",path);
FMDatabase *db = [FMDatabase databaseWithPath:path];
if(![db open])
{
NSLog(#"Could not open DB, try again");
return nil;
}
FMResultSet *results = nil;
results = [db executeQuery:#"SELECT * FROM cus"];
NSLog(#"result %# ",results);
while([results next])
{
Customer *customer = [[Customer alloc] init];
customer.customerId = [results intForColumn:#"id"];
customer.firstName = [results stringForColumn:#"firstname"];
NSLog(#"Customer object %#", customer);
[customers addObject:customer];
[customer release];
}
[db close];
return customers;
}

I have had this same problem but was managed to resolve this by setting up the path correctly. So, there could be something wrong in the path specification. Do make sure that your database path is perfect. And as everyone suggests, I recommend you to use error statements to narrow down the issue. Wishes!!

Related

Issue with passing variables to FMDB

In my app I'm using FMDB to query my sqlite database. I'm passing variables from one view to another and at the end all the selections the variables are filled with the values selected. On the results page I can show these values in label's fine. But the moment I pass them to FMDB to query the database I don't get any values returned. It crashes and says that the array is 0 which I know it's not.
Code sample below.
- (NSMutableArray *) getChoices
{
NSMutableArray *choices = [[NSMutableArray alloc] init];
FMDatabase *db = [FMDatabase databaseWithPath:[Utility getDatabasePath]];
[db open];
NSString *capsChoiceOne = #"CHOICE 1";
NSString *capsChoiceTwo = #"CHOICE 2";
NSString *capsChoiceThree = #"CHOICE 3";
NSString *capsChoiceFour = #"CHOICE 4";
FMResultSet *results = [db executeQueryWithFormat:#"SELECT * FROM allitems WHERE choice1=%# AND choice2=%# AND choice3=%# AND choice4=%#"
,capsChoiceOne,capsChoiceTwo,capsChoiceThree,capsChoiceFour];
while([results next])
{
Choices *choice = [[Choices alloc] init];
choice.result = [results stringForColumn:#"result"];
[choices addObject:choice];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Your Result"
message:choice.result
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
[db close];
return choices;
Now the above code will bring back the result in the Alert View. But the moment I change one of the values to a variable it crashes and say's there was 0 results in my array. I've put the code below for how I'm inserting the variable.
NSString *capsChoiceOne = self.choiceOneSelected.uppercaseString;
the self.choiceOneSelected.uppercaseString contains the same as the hard coded version but doesn't work.
Any help would be grateful.
Thank you
Check whether self.choiceOneSelected.uppercaseString; is not nil.
Also your query have some issues, you need to wrap string values inside '
So use:
FMResultSet *results = [db executeQueryWithFormat:#"SELECT * FROM allitems WHERE choice1='%#' AND choice2='%#' AND choice3='%#' AND choice4='%#'"
,capsChoiceOne,capsChoiceTwo,capsChoiceThree,capsChoiceFour];

How to Show a String instead of address in textView

i am trying to get a random string from database i have tried to convert array in a String but when i click button i only get address can anyone help me how to show that string in my button action?
- (IBAction)randBtn:(id)sender {
SendQuoteVC *svc= [[SendQuoteVC alloc]initWithNibName:#"SendQuoteVC" bundle:nil];
DBHandler *db =[[DBHandler alloc]init];
arr =[db randomQuote];
NSMutableString * show = [[NSMutableString alloc] init];
for (NSObject * obj in arr)
{
[show appendString:[obj description]];
}
NSLog(#"The concatenated string is %#", show);
NSString *rs =[NSString stringWithFormat:#" %#",show];
svc.quote=rs;
[self.navigationController pushViewController:svc animated:YES];
}
and my log message is
2012-12-26 17:02:46.062 SendQuote[2281:c07] QUERY: SELECT * FROM quotes ORDER BY RANDOM() LIMIT 1
2012-12-26 17:02:46.097 SendQuote[2281:c07] txtQuote is (
"<quoteDC: 0xa9a94c0>"
)
2012-12-26 17:02:46.100 SendQuote[2281:c07] rand is (
"<quoteDC: 0xa9a94c0>"
)
i have changed my user entity class to quoteDC class and my Db function is
-(NSMutableArray *)randomQuote{
NSMutableArray *dataArray =[[NSMutableArray alloc]init];
NSString * sqlStr=[NSString stringWithFormat:#"SELECT * FROM quotes ORDER BY RANDOM() LIMIT 1"];
sqlite3_stmt *ReturnStatement = (sqlite3_stmt *) [self getStatement: sqlStr];
while (sqlite3_step(ReturnStatement)==SQLITE_ROW)
{
#try
{
quoteDC *worddc = [[quoteDC alloc] init];
NSString *userid = [NSString stringWithUTF8String:(char *)sqlite3_column_text(ReturnStatement, 0)];
NSString *name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(ReturnStatement, 1)];
worddc.quote_id=[userid integerValue];
worddc.quotes=name;
[dataArray addObject:worddc];
}
#catch (NSException *ept) {
NSLog(#"Exception in %s, Reason: %#", __PRETTY_FUNCTION__, [ept reason]);
}
}
return dataArray;
}
the [db randomQuote] method returns an array of users not strings, you can typecast it to user object than get your desired property out of it!
It seems like your array is an array of objects of some user class rather than array of strings.
Hence the call to
[obj description]
is returning an object instead of a string.
You would need to override the description method in your user class, and return string.
This code makes the issue:
for (NSObject * obj in arr)
{
[show appendString:[obj description]];
}
Because your entity class don't have a property like description.
Instead of this write:
for (quoteDC * obj in arr)
{
[show appendString:[obj quotes]];
}
Try this i think it work for u...
- (IBAction)randBtn:(id)sender {
SendQuoteVC *svc= [[SendQuoteVC alloc]initWithNibName:#"SendQuoteVC" bundle:nil];
DBHandler *db =[[DBHandler alloc]init];
arr =[db randomQuote];
NSString *rs =(NSString *)arr;
svc.quote=rs;
[self.navigationController pushViewController:svc animated:YES];
}
Instead of for (NSObject * obj in arr) use the object that is stored in arr.
I guess it is some DBHandler object. So use
for (DBHandler * dbh in arr){
[show appendString:[dbh thePropertyYouWantToAppend]];
}

sqlite3 and fmdb nested FMResultSet is possible?

I'm trying to iterator through a master detail sort of tables and I'd like to populate the master/detail structures as I go. Apparently when I nest result sets I get a BAD Access exception:
FMDatabase *db = self.database;
[db open];
db.traceExecution = YES;
db.logsErrors = YES;
FMResultSet *rs = [db executeQuery:#"select group_id, label from main.preference_group order by group_id"];
while ([rs next])
{
PreferenceGroup *pg = [[PreferenceGroup alloc] init];
pg.group_id = [rs intForColumn:#"group_id"];
pg.label = [rs stringForColumn:#"label"];
pg.translatedLabel = NSLocalizedString(pg.label, nil);
NSMutableArray * prefs = [[NSMutableArray alloc] init];
[prefGroups addObject:prefs];
FMResultSet *rs2 = [db executeQuery:#"select pref_id, label, value from main.preference where group_id = ? order by pref_id", pg.group_id, nil];
while ([rs2 next])
{
Preference * pref = [[Preference alloc] init];
pref.group_id = pg.group_id;
pref.pref_id = [rs2 intForColumn:#"pref_id"];
pref.label = [rs2 stringForColumn:#"label"];
pref.value = [rs2 stringForColumn:#"value"];
pref.translatedLabel = NSLocalizedString(pref.value, nil);
[prefs addObject:pref];
}
[rs2 close];
}
[rs close];
[db close];
In the rs2 (second result set) I get the EXEC_BAD_ACCESS within FMDatabase class.
Is this a restriction of sqlite3/fmdb or am I doing something wrong here?
I just found what I did wrong. I was passing a int as part of the second query. I had to convert it to NSNumber:
FMResultSet *rs2 = [db executeQuery:#"select pref_id, label, value from main.preference where group_id = ? order by pref_id", [NSNumber numberWithInt:pg.group_id], nil];
So that means, YES, sqlite3/fmdb does support nested queries! :-)
I'm using FMDB and SQLITE3 as well, and I find nested queries work:
(I'm not claiming the code hint below is good, never mind the format, please)
Both Master and Detail tables have a column called 'id'
FMResultSet *rso = [database executeQuery:#"select * from master order by id"];
while ([rso next])
{
NSInteger masterId = [rso intForColumn:#"id"];
NSString *q3 = [[NSString alloc] initWithFormat:
#"select * from detail where masterid = %d order by id", masterId, nil ];
FMResultSet *rsa = [database executeQuery:q3 ];
while ([rsa next])
{
NSInteger detailId = [rsa intForColumn:#"id"];
//
// here do something with masterId and detailId
}
}
This was a pleasant surprise, actually. I was halfways expecting to have to first query all master records, and then loop through them in App memory to pick up the details from SQlite3.
But the above construct works fine.

SQLite Changes Not Saved

I'm using SQLite in iOS 4 on an iPhone, but the changes made by my update statements aren't saved. At first thought perhaps quitting the app might be deleting the database somehow, but they're not even persisted during the same session. The code to initialize my database is (using FMDB):
-(SQLiteDal*) init {
pool = [[NSAutoreleasePool alloc] init];
self = [super init];
if(self != nil){
// Setup some globals
NSString *databaseName = [self getDbPath];
NSLog([NSString stringWithFormat:#"db path: %#", databaseName]);
db = (FMDatabase *)[FMDatabase databaseWithPath:databaseName];
if (![db open]) {
NSLog(#"Could not open db.");
[pool release];
return 0;
}
}
//[self checkAndCreateDatabase];
return self;
}
#pragma mark DB Maintenance
-(NSString *)getDbPath {
NSString *databaseName = #"myapp.db";
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databaseName = [documentsDir stringByAppendingPathComponent:databaseName];
return databaseName;
}
Both of these methods are called to create the database, then to insert to a table I call:
[db executeQuery:#"INSERT INTO MyTable (Name, Description, Area, Price, ID) VALUES (?,?,?,?,?)",
f.Name,
f.description,
f.area,
f.price,
f.id];
The problem is, when I come to read from MyTable using the statement below, I never get anything back:
FMResultSet *rs = [db executeQuery:#"SELECT * FROM MyTable WHERE ID = ?", id];
while ([rs next]) {
//.. this is never called
As far as I can see I'm not missing anything out, and the DB seems to be in a writable location.
When inserting you need to call executeUpdate not executeQuery. Also you should call beginTransaction and then commit, like this:
[_dbPointer beginTransaction];
BOOL isInserted = [_dbPointer executeUpdate:[NSString stringWithFormat:#"INSERT INTO MyTable (Name, Description, Area, Price, ID) VALUES(?,?,?,?,?);", f.Name,
f.description,
f.area,
f.price,
f.id]];
[_dbPointer commit];

FMDB Result set contains null iphone

I am using FMDB for my application to store data in sqlite. Here is my code
from AppDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
FMDatabase* db = [FMDatabase databaseWithPath:#"/tmp/sql.sqlite"];
if (![db open]) {
NSLog(#"Could not open db.");
}
NSLog(#"DB opened successfully");
// full code not shown here
}
I have following code in ViewController
-(IBAction)insertButtonClicked:(id)sender
{
NSLog(#"in insertButtonCLicked");
[db beginTransaction];
[db executeUpdate:#"insert into sample (url) values (?)",#"google'"];
[db commit];
}
-(IBAction)displayButtonClicked:(id)sender
{
NSLog(#"in DisplayCLicked");
FMResultSet *rs = [db executeQuery:#"select url from sample"];
NSLog(#"Rs contains => %#",rs);
while( [rs next])
{
NSLog(#"%#",[rs stringForColumn:#"url"]);
}
[rs close];
}
When i run this code i get rs as null as shown in following (this is o/p from console)
2011-03-07 07:30:06.919 InsertDataSample[3092:20b] DB opened successfully
2011-03-07 07:30:13.341 InsertDataSample[3092:20b] in insertButtonCLicked
2011-03-07 07:30:16.860 InsertDataSample[3092:20b] in DisplayCLicked
2011-03-07 07:30:16.860 InsertDataSample[3092:20b] Rs contains => (null)
Plz help me friends. I am working on FMDB from many days but i am unable to use FMDB .
Thanks in advance
Insert this just after your query and FMDB will probably tell you exactly what the problem is.
if ([db hadError]) {
NSLog(#"DB Error %d: %#", [db lastErrorCode], [db lastErrorMessage]);
}
Update:
Running this:
FMDatabase *db = [FMDatabase databaseWithPath:#"/tmp/sql.sqlite"];
[db executeUpdate:#"create table sample (url TEXT);"];
[db executeUpdate:#"insert into sample (url) values(?);", #"google'"];
FMResultSet *rs = [db executeQuery:#"select url from sample;"];
while ([rs next]) {
NSLog(#"%#", [rs stringForColumn:#"url"]);
}
[rs close];
[db close];
produced this output:
2011-03-06 12:38:59.831 test[93163:207] google'