Sqlite3 INSERT INTO Question × 377 - objective-c

I am creating an exercise app that will record the weight used and the number of "reps" the user did in 4 "Sets" per day over a period of 7 days so the user may view their progress.
I have built the database table named FIELDS with 2 columns ROW and FIELD_DATA and I can use the code below to load the data into the db. But the code has a sql statement that says,
INSERT OR REPLACE INTO FIELDS (ROW, FIELD_DATA)VALUES (%d, '%#');
When I change the statment to:
INSERT INTO FIELDS (ROW, FIELD_DATA)VALUES (%d, '%#');
Nothing happens. That is no data is recorded in the db.
Below is the code:
#define kFilname #"StData.sqlite3"
- (NSString *)dataFilePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilname];
}
-(IBAction)saveData:(id)sender;
{
for (int i = 1; i <= 8; i++)
{
NSString *fieldName = [[NSString alloc]initWithFormat:#"field%d", i];
UITextField *field = [self valueForKey:fieldName];
[fieldName release];
NSString *insert = [[NSString alloc] initWithFormat:
#"INSERT OR REPLACE INTO FIELDS (ROW, FIELD_DATA)
VALUES (%d, '%#');",i, field.text];
// sqlite3_stmt *stmt;
char *errorMsg;
if (sqlite3_exec (database, [insert UTF8String],
NULL, NULL, &errorMsg) != SQLITE_OK)
{
// NSAssert1(0, #"Error updating table: %s", errorMsg);
sqlite3_free(errorMsg);
}
}
sqlite3_close(database);
}
So how do I modify the code to do what I want? It seemed like a simple sql statement change at first but obviously there must be more. I am new to Objective-C and iPhone programming.
I am not new to using sql statements as I have been creating web apps in ASP for a number of years.
Any help will be greatly appreciated, this is driving me nuts!

Suggestions:
write an insert statement with hardcoded values to see if the insert works
your filename has no path. does it assume the current directory when executed? what directory is it running from?
write a message to the screen if possible to see what the values you're getting are. Are they correct?

Related

Save information from NSTextField in sqlite database (objective-c)

Since some months I am interested in coding. At the moment I am working on a programm which saves informations from textfields in a sqlite3 database. I am programming this project on Objective C in Xcode for Mac. Unfortunately I have problems in inserting data into my database. When I insert it and open my database in Terminal I just get this information in the cell for the string:
Here ist my code:
NSString *Bt = [NSString stringWithFormat:#"%#", Text]; //Theres a IBOutlet NSTextField *Text; in the Header data of the class
dbPath=#"/Users/Desktop/database.db";
if (sqlite3_open([dbPath UTF8String], &database)!=SQLITE_OK) {
sqlite3_close(database);
NSLog(#"Failed to open database");
} else {
char *errorMessage;
NSString *insertSQL = [NSString stringWithFormat:#"INSERT INTO table (table) VALUES (\"%#\")", Bt];
const char *insert_stmt = [insertSQL UTF8String];
if(sqlite3_exec(database, insert_stmt, NULL, NULL, &errorMessage)==SQLITE_OK){
NSLog(#"Data inserted");
[db_status setFloatValue:5];
}
}
}
It would be great if somebody can help me. I think it is just a small error but I don´t get the problem ;(
Best regards,
Robby
by the looks of your IBOUTLET connection, how you have your code, Bt is equal to the TextField. But what you want is the text value in the TextField. so you would use this: NSString *Bt = [NSString stringWithFormat:#"%#", Text.stringValue]; NSTextField has a property named stringValue and this will return the NSString that contains the value inside the textfield, Text.
Allowing Quotation Marks in Your Database
So easiest way, i can think of, is having a category method on NSString. So wherever you're going to save string or text from the user to your database, you would use this function to then insert into your format statement. and example shown below:
Header File of NSString Category
#interface NSString (STRING_)
/**
* Allowing Qoutation marks inside a string to be saved in a SQL column with the string format sourrounded by #"\"%#\"". this will not modify the string, only return a modified copy
* #return NSString *
*/
- (NSString *)reformatForSQLQuries;
#end
Implantation File of NSString Category
#implementation NSString (STRING_)
- (NSString *)reformatForSQLQuries {
NSString *string = self;
//Depending on how you "wrap" your strings to format the string values into your INSERT, UPDATE, or DELETE queries, you'll only have to use one of these statements. YOU DO NOT NEED BOTH
//Use this if you have your format as: '%#'
string = [string stringByReplacingOccurrencesOfString: #"'" withString: #"''"];
//Use this if you have your format as: \"%#\"
string = [string stringByReplacingOccurrencesOfString: #"\"" withString: #"\"\""];
return string;
}
example
...
NSString *insertSQL = [NSString stringWithFormat:#"INSERT INTO table (table) VALUES (\"%#\")", [Bt reformatForSQLQuries]];
...
I got the solution ! It´s false to write:
NSString *Bt = [NSString stringWithFormat:#"%#", Text];
The solution is to get the value from the NSTextField:
NSString *Bt = [NSTextField stringValue];
What I still don´t understand is why it´s not possible to save Strings which include this symbol: "". For example:
The database saves this: I like programming.
But not this: I like "programming".
Can somebody explain me why ?

sqlite3 create table problems

I have an app I'm developing that will store soccer match statistics but I'm having trouble with my sqlite database. My save method is this :
-(void) saveData{
NSString *databasePath;
sqlite3_stmt *statement;
const char *dbpath =[databasePath UTF8String];
char *errMsg;
NSString *games;
games= #"games";
NSString *entree =[NSString stringWithFormat:#"create table if not exists %#(id integer, home text, away text)", games];
if (sqlite3_open(dbpath, &_gameFile)==SQLITE_OK){
if(sqlite3_exec(_gameFile, [entree UTF8String], NULL, NULL, &errMsg) !=SQLITE_OK){
NSLog(#"executing %s", sqlite3_errmsg(_gameFile));
} else {
NSLog(#"table created (%#)", entree);
}
}
sqlite3_close(_gameFile);
if (sqlite3_open(dbpath, &_gameFile)==SQLITE_OK){
NSString *insertSQL = [NSString stringWithFormat:#"INSERT INTO games (id, home, away) VALUES (\"%#\",\"%#\",\"%#\")", dataPoints[0], dataPoints[1], dataPoints[2]];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(_gameFile, insert_stmt, -1, &statement, NULL);
int rc =sqlite3_step(statement);
if(sqlite3_step(statement) == SQLITE_DONE){
NSLog(#"success");
NSLog(#"tried to enter %#" , insertSQL);
} else if(sqlite3_step(statement) == SQLITE_MISUSE){
NSLog(#"%#", insertSQL);
NSLog(#"Error %s while preparing statement", sqlite3_errmsg(_gameFile));
}
sqlite3_finalize(statement);
sqlite3_close(_gameFile);
}
}
This produces the following entries in the log:
2014-12-10 15:25:32.752 Footy Predictor[1718:513765] table created (create table if not exists games(id integer, home text, away text))
2014-12-10 15:25:32.759 Footy Predictor[1718:513765] INSERT INTO games (id, home, away) VALUES ("1446","Den Haag","Excelsior")
2014-12-10 15:25:32.760 Footy Predictor[1718:513765] Error no such table: games while preparing statement
I'm not really sure where I'm going wrong as the log says table created, and then says no such table.
Any help would be greatly appreciated.
I don't have an explicit answer for you because there are quite a few things that can go wrong with sqlite.
The main thing I can see is that you are not initialising databasePath. This needs to be a path to the .db file e.g. ~/Desktop/myDatabase.db.
1) I assume that you only want to process the statement once and you are actually inserting it 3 times. you need to check the value of rc i.e. only call sqlite3_step once and then put rc into the if statements :
int rc =sqlite3_step(statement);
if(rc == SQLITE_DONE){
NSLog(#"success");
NSLog(#"tried to enter %#" , insertSQL);
} else {
NSLog(#"%#", insertSQL);
NSLog(#"Error %s while preparing statement", sqlite3_errmsg(_gameFile));
}
2) Check the return value of sqlite3_prepare_v2 for success.
3) You neeeeed to normalise your statements (documentation for sqlite3_bind), otherwise you will run into problems when your users enter wildcard characters e.g. "?" or statements like "DROP"
4) Have you considered using Core Data. It is sooo much easier (although not ideal for everyone's needs I know).

Return strings in sequence from NSMutableArray [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I have a NSMutableArray with comma separated strings for an objective-c iphone application (iOS SDK 6.0). I need a simple function that, when triggered, returns a string, one at a time, from string 0 onwards. To give you some context, a user would click a button, and for every click a new string is returned, in order, from the Array. It's a list of previously saved "favourite quotes". The string is displayed in a UITextView.
Ideally, I would also have a function for reversing, i.e. going backwards in the array from the current position.
This might be pretty basic, but I seem to only be able to find more advanced implementations that I'm unable to translate into this looping backwards and forwards in an Array of strings.
EDIT: Current code for this function below. I need to add the part where one string at a time is returned from the array (allRows) and displayed in a textview
- (IBAction)nextQoute:(id)sender {
const char *dbpath = [_databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &_qoutesDB) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat:
#"SELECT qoutesSaved FROM qoutes"];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(_qoutesDB,
query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
NSMutableArray *allRows = [[[NSMutableArray alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *qouteField = [[NSString alloc]
initWithUTF8String:
(const char *) sqlite3_column_text(
statement, 0)];
NSString *str = [NSString stringWithFormat:#"%#", qouteField];
[allRows addObject:str];
[qouteField release];
}
Very thankful for help!
You mention that you are new to Objective C, and based on how I read what you're describing, I wonder if you are making this a lot more complicated than it needs to be. Items in an array (that is, NSArray, or NSMutableArray) aren't "seperated" by anything - different items in an array are accessed by their order in the array, called an index. So in your code, when you build allRows, each str that you put into it gets put into its own index, and to get it back out of the array, you just use that index.
For example, let's pretend your quotes you are pulling from your database are:
"Here's looking at you kid"
"I'll be back"
"It's a trap"
If they are put into the array in that order, and you want to put "It's a trap" into a textfield (called myTextField), you just write
myTextField.text = [allRows objectAtIndex:2];
In the end, that means what you probably want to do for your app is keep a counter you pass to objectAtIndex. When the user clicks the forward button, increase the count. When they click the back button, decrease the count. Then, call the code I put above, except instead of sending the value 2, send your counter variable. As mentioned in the comments to H2CO3s answer, make sure you put some validation in there to prevent your count from going beyond the limits of your array, or you'll get a nasty crash. If this is indeed what you are trying to do and you are still confused, I can add some more code.
I'm not too familiar with accessing a sqlite database the way you do here (I use CoreData, so the calls are very different), so perhaps I am completely mistaken about what you are trying to do here - but this seems like a very simple task that is being very overcomplicated.
You can just keep track of the string index in an instance variable (or if you don't have an object to work with because you write a class method or a function and not an instance method, then you can use a static local variable too).
#interface Foo: NSObject {
NSInteger index;
NSArray *strings;
}
// ...
- (NSString *)nextString
{
return index < strings.count ? strings[index++] : nil;
}
- (NSString *)previousString
{
return index > 0 ? strings[--index] : nil;
}
You can fetch the whole data in database.And store it one array
declare these two objects.
#interface YourClassName: NSObject {
NSInteger stringIndex;
NSArray *quoteFieldDataArr;
}
NSMutableArr *quoteFieldDataArr=[self fetchDataFromDataBase];
-(NSMutableDictionary *)fetchDataFromDataBase
{
const char *dbpath = [_databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &_qoutesDB) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat:
#"SELECT qoutesSaved FROM qoutes"];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(_qoutesDB,
query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
NSMutableDictionary *allRows = [[[NSMutableDictionary alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *qouteField = [[NSString alloc]
initWithUTF8String:
(const char *) sqlite3_column_text(
statement, 0)];
NSString *str = [NSString stringWithFormat:#"%#", qouteField];
[allRows addObject:str];
[qouteField release];
return nil;
}
// Load Next String
- (NSString *)loadNextString
{
return stringIndex < quoteFieldDataArr.count ? quoteFieldDataArr[stringIndex++] : nil;
}
- (NSString *)loadpreviousString
{
return stringIndex > 0 ? quoteFieldDataArr[--stringIndex] : nil;
}

sqlite3_prepare_v2 is getting SQLITE_ERROR

I have been at this for hours and MUST get this working! It is holding up an iPhone app release... My first time using SQLite. I have followed all the advice and yet my sqlite3_prepare_v2 call gets a SQLITE_ERROR (1) every time!
Here is my code from my controller:
NSString *query = #"SELECT * FROM QandA ORDER BY random() LIMIT 1";
// const char *sqlStatement = "SELECT * FROM QandA ORDER BY random() LIMIT 1";
sqlite3_stmt *compiledStatement;
// sqlite3_stmt *statement;
int prepareStatus = sqlite3_prepare_v2(database, [query UTF8String],
-1, &compiledStatement, NULL);
if (prepareStatus == SQLITE_OK) {...
You'll note that I've tried using a "char *" also to no avail (among other attempts). My database opens fine with:
databaseName = #"Facts.sqlite";
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
NSLog(#"databasePath = %#", databasePath);
int dbOpenStatus = sqlite3_open_v2([databasePath UTF8String], &database, SQLITE_OPEN_READWRITE, NULL);
From my controller interface:
NSString *databaseName;
NSString *databasePath;
I've checked in the debugger and everything looks good, but the prepare statement fails. I don't know how to log the statement it is trying to compile... I assume/hope it is just what my SELECT says.
Can anyone help? I'm desperate. Mark
Found the answer here. I had to use this instead for the path to the DB file:
[[NSBundle mainBundle]pathForResource:#"Facts"extension:#"sqlite"];
This gave a slightly different path (one extra directory) - once I used that it worked! Hope this helps someone else... I spent many hours on this.
Please note that the above is slightly inaccurate, the ofType should be used not extension, and the ofType obviously needs to match your file extension.
If your DB is named "mysqldatabase.sql" change your path URL to:
databasePath = [[NSBundle mainBundle]pathForResource:#"mysqldatabase" ofType:#"sql"];
The code seems to be fine, might be a silly question but have you created the QandA table inside of the database?

NSMutableArray does not print well with several lines of string

while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *araci2 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
[dbarray addObject:araci2];
NSLog(#"DB ITEMS: %#",dbarray);
}
First of all, I try to get a description longer than a line from db. While part of the value appears meaningful, some of the characters of those values are absurd like "00fu". How can I print them in proper fashion ?
I got over gentles. .. I created class and received those values by class variable.