How to get/delete multiple rows in SQLITE table in iOS? - ios

My table in SQLITE is in the following format.
id name date height
1 tt 12-2-15 120
2 ss 15-3-15 110
3 tt 14-5-15 120
....
10 tt 19-6-15 130
(1)I like to get all rows under name tt in one instruction, then put into two dimensional array. How can i implement it?
(2)How to delete all rows under name tt in one instruction?
My code is in iOS. I couldn't find solution easily.
EDIT:
Just to share what I implement.
NSString *databasePath;
NSString *docsDir;
NSArray *dirPaths;
//Database
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
databasePath = [[NSString alloc]initWithString:[docsDir stringByAppendingPathComponent: #"RECORDS.db"]];
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath,& RECORDS) == SQLITE_OK)
{
retval = [[NSMutableArray alloc] init];
NSString *query = [NSString stringWithFormat:#"SELECT id, nameid, date, height FROM RECORD WHERE nameid=\"%#\"", currentNameID];
const char *query_stmt = [query UTF8String];
if (sqlite3_prepare_v2(RECORDS, query_stmt, -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
char *date = (char *) sqlite3_column_text(statement, 1);
int height = (int) sqlite3_column_text(statement, 2);
NSString *name = [[NSString alloc] initWithUTF8String:date];
HeightInfo *info = [[HeightInfo alloc] initWithInfos:name withheight:(int)height];
[retval addObject:info];
}
sqlite3_finalize(statement);
sqlite3_close(RECORDS);
}
}
Thanks

Do you need help with the SQL or the ios framework?
The SQL is pretty straightforward;
select id, name, date, height from mytablename where name = "tt";
delete from mytablename where name == "tt";
Practice the commands on the command line so you see how they work.
For processing your data look at the great examples by Ray Wenderlich;
http://www.raywenderlich.com/913/sqlite-tutorial-for-ios-making-our-app

Related

Issues when reading from a database in an iPhone app

I am making an iPhone app for a school project that reads and writes to a database. I have managed to get my code to write to it but it won't read. Below is the code I'm using to read:
NSString * paths=[self getWritableDBPath];
const char *dbpath = [paths UTF8String];
sqlite3_stmt *statement;
static sqlite3 *database = nil;
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat: #"SELECT questionright, totalquestions, FROM results", nil];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
//code...
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
}
Here is getWritableDBPath:
-(NSString *) getWritableDBPath {
NSString *myDB = #"appData.db";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:myDB];
}
The reason it doesn't work is that the sqlite3_prepare_v2 if statement is never satisfied.
When I write to the database I copy it to documents.
I am quite sure the results table exists as I am able to write to it. Here is the original sql statement:
DROP TABLE IF EXISTS "Questions";
CREATE TABLE "Questions" ("QuestionID" INTEGER PRIMARY KEY NOT NULL , "Question" TEXT, "RightAnswer" TEXT, "WrongAnswer1" TEXT, "WrongAnswer2" TEXT, "Done" BOOL, "Catagory" TEXT, "Audio" INTEGER);
DROP TABLE IF EXISTS "Results";
CREATE TABLE "Results" ("ResultID" INTEGER PRIMARY KEY NOT NULL , "QuestionRight" INTEGER, "TotalQuestions" INTEGER, "Catagory" TEXT);
I did find a similar question on here but didn't think the answers were that relevant to me.
Thanks for your help.
If you want my advice, don't use the sqlite c libraries directly if you don't really need that, you can use FMDB library and get rid of all the c headache
https://github.com/ccgus/fmdb
You can simply do it like this
FMDatabase *db = [FMDatabase databaseWithPath:#"your full db path in documents goes here"];
if (![db open]) {
return;
}
FMResultSet *s = [db executeQuery:#"Your query goes here"];
if ([s next]) {
int totalCount = [s intForColumn:#"totalCount"];
}

unable to update or insert a row in a table

I want to update a row in my iPhone app. Below is the code. It shows in my log that query is executed and row has been updated, but when I excess that table, it seems to be empty. And also it always updates a row even if I am trying to enter a row with new id, it should insert instead of updating in this case.
//create local database
NSString *docsDir = NULL;
NSArray *dirPaths = NULL;
sqlite3 *localDB = NULL;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"localscentsy1.db"]];
NSLog(#"%#",databasePath);
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement = NULL;
if (sqlite3_open(dbpath, &localDB) == SQLITE_OK)
{
NSString *updateSQL = [NSString stringWithFormat:#"UPDATE Ratings set rating = '%d' WHERE perfume_id = ?",
(int)rating];
const char *update_stmt = [updateSQL UTF8String];
if(sqlite3_prepare_v2(localDB, update_stmt, -1, &statement, NULL ) ==SQLITE_OK){
sqlite3_bind_int(statement, 1, tappedItem.perfumeId);
}
char* errmsg;
sqlite3_exec(localDB, "COMMIT", NULL, NULL, &errmsg);
if(SQLITE_DONE != sqlite3_step(statement)){
NSLog(#"Error while updating. %s", sqlite3_errmsg(localDB));
NSLog(#"query failed: %s", sqlite3_errmsg(localDB));
NSLog(#"%#",#"update unsuccessfull");
NSLog(#"New data, Insert Please");
sqlite3_stmt *statement2 = NULL;
NSString *insertSQL = [NSString stringWithFormat:
#"INSERT INTO Ratings (perfume_id,rating) VALUES (\"%d\",\"%d\")",
tappedItem.perfumeId,
(int)rating];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(localDB, insert_stmt, -1, &statement2, NULL);
if (sqlite3_step(statement2) == SQLITE_DONE)
{
NSLog(#"New data, Inserted");
}
sqlite3_finalize(statement2);
}
else{
NSLog(#"%#",#"update successfull");
sqlite3_finalize(statement);
}
sqlite3_close(localDB);
}
Any help will be appreciated. I am new at ios development and this code is taking so much of my time. Here is my log which always says "update successful"
CyberGenies/Library/Application Support/iPhone Simulator/7.0/Applications/24D2FEE2- DBE6-441A-AC79-1F2D57F96C88/Documents/localscentsy1.db
2014-07-27 01:03:26.612 Scentsy Squirrel[19008:a0b] update successfull
Have you seen if the db really has the structure? Some times when you start doing queries in an empty db (I mean not even tables) the query itself build the structure you are giving it on the query. You can check by compiling on the simulator and look for the db in the Mac finder.

sort SQL data in xcode

I am trying to sort / order SQL data in my iOS app. the database is working fine. i can add data, display in tableview, edit, delete everything is working fine. just can't sort. below is the code i am using.
-(void)sortTable
{
//CHECKING DIRECTORY AND CREATING DATABASE CODE STARTS
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths [0];
//Build the path to the database file
_databasePath = [[NSString alloc]initWithString:[docsDir stringByAppendingPathComponent:#"events.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: _databasePath] == NO)
{
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_eventDB) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt =
"CREATE TABLE IF NOT EXISTS EVENTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, EVENT TEXT, EVENTDATE TEXT)";
//closing database after creating
if (sqlite3_exec(_eventDB, sql_stmt, NULL, NULL, &errMsg) !=SQLITE_OK)
{
// sqlite3_close(_eventDB);
}
}
}
//CHECKING DIRECTORY AND CREATING DATABASE CODE ENDS
//sort sql table
sqlite3_stmt *statement;
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_eventDB) == SQLITE_OK)
{
NSString *sortSQLTable = [NSString stringWithFormat:#"SELECT EVENT FROM EVENTS ORDER BY EVENT"]; // EVENTS is the table name and EVENT is the column.
const char *sort_stmt = [sortSQLTable UTF8String];
sqlite3_prepare_v2(_eventDB, sort_stmt, -1, &statement, NULL);
}
}
I am executing this void statement in viewDidLoad.
I have searched a lot. tried different things. just could not make it work. can someone help please.
UPDATE:
I just found that the ORDER BY query is actually sorting the table, but its not saving the database.
any idea how i can save the database after sorting?
If you are looking to sort data to display on your tableview you could use a NSSortDescriptor.
Here is the documentation from Apple on how to use them.
The gist though is something like ..
//array of People objects with properties of firstName and lastName just for example
NSArray *firstNames = #[ #"Jan", #"Steve", #"Jay", #"Mike" ];
NSArray *lastNames = #[ #"Joker", #"Jones", #"Smith", #"Pham" ];
NSMutableArray *people = [NSMutableArray array];
[firstNames enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
Person *person = [[Person alloc] init];
person.firstName = [firstNames objectAtIndex:idx];
person.lastName = [lastNames objectAtIndex:idx];
[people addObject:person];
}];
//make the descriptor
NSSortDescriptor *firstNameSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"firstName"
ascending:YES ];
//sort the array using the descriptor
NSLog(#"By first name: %#", [people sortedArrayUsingDescriptors:#[firstNameSortDescriptor]]);

Objective-c sql error - error with statement look like empty result

hi i'm getting stuck with some code. i have a file catalog.db and a class that let me work with it. When i try to retrieve datas from the db it seems like it's empty. With several nslog i can see that it connect and enter the database, i can see it enter in it but then it won't get any value from it.
i tried to see if the query was wrong with an external DB manager software and the query works fine...
this is my class
#import "DBAccess.h"
sqlite3* database;
#implementation DBAccess
-(id)init{
self = [super init];
if (self){
[self initializeDatabase];
}
return self;
}
-(void)initializeDatabase{
NSString *path = [[NSBundle mainBundle]pathForResource:#"catalog" ofType:#"db"];
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) { NSLog(#"Opening Database"); }
else {
sqlite3_close(database);
NSAssert1(0, #"FAILED to open database '%s'", sqlite3_errmsg(database));
}
}
-(void)closeDatabase{
if (sqlite3_close(database) != SQLITE_OK){
NSAssert1(0, #"ERROR to close databse: '%s'", sqlite3_errmsg(database));
}
}
-(NSMutableArray *)getAllProduct{
NSMutableArray *products = [[NSMutableArray alloc]init];
const char *sql = "SELECT product.ID,product.Name, Manufacturer.name, product.details,product.price, product.quantityOnHand,country.country,product.image FROM product,manufacturer,country WHERE manufacturer.manufacturerID = product.manufacturerID and product.countryOfOriginID = country.countryID";
sqlite3_stmt *statement;
int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
NSLog(#"sqlResult: %d", sqlResult);
if (sqlResult == SQLITE_OK){
NSLog(#"sql step statement: %d",sqlite3_step(statement));
NSLog(#"QUERY DONE");
while (sqlite3_step(statement) == SQLITE_ROW){
NSLog(#"TEST");
Product *product = [[Product alloc]init];
char *name = (char *)sqlite3_column_text(statement, 1);
NSLog(#"n %s",name);
char *manufacturer = (char *)sqlite3_column_text(statement, 2);
NSLog(#"m %s", manufacturer);
char *details = (char *)sqlite3_column_text(statement, 3);
NSLog(#"d %s", details);
char *countryoforigin = (char *)sqlite3_column_text(statement, 6);
NSLog(#"%s", countryoforigin);
char *image = (char *)sqlite3_column_text(statement, 7);
NSLog(#"%s", image);
product.ID = sqlite3_column_text(statement, 0);
product.name = (name)?[NSString stringWithUTF8String:name]:#"";
product.manufacturer = (manufacturer)?[NSString stringWithUTF8String:manufacturer]:#"";
product.details = (details)?[NSString stringWithUTF8String:details]:#"";
product.price = sqlite3_column_double (statement, 4);
product.quantity = sqlite3_column_int(statement, 5);
product.countryOfOrigin = (countryoforigin)?[NSString stringWithUTF8String:countryoforigin]:#"";
product.image = (image)?[NSString stringWithUTF8String:image]:#"";
[products addObject:product];
}
sqlite3_finalize(statement);
}
else {
NSLog(#"Problem with database %d",sqlResult);
}
return products;
}
#end
this is what i get in my console
2013-08-14 12:38:58.505 Catalog[1642:c07] Opening Database
2013-08-14 12:38:58.508 Catalog[1642:c07] sqlResult: 0
2013-08-14 12:38:58.509 Catalog[1642:c07] sql step statement: 101
2013-08-14 12:38:58.509 Catalog[1642:c07] QUERY DONE
2013-08-14 12:38:58.510 Catalog[1642:c07] ()
what can be my problem? thanks
Here
NSLog(#"sql step statement: %d",sqlite3_step(statement));
you fetch already the first row (without using the result).
1)Copy the database to your documents directory...
-(void) checkAndCreateDatabase{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:#"test.sqlite"];
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
success = [fileManager fileExistsAtPath:databasePath];
// If the database already exists then return without doing anything
if(success) return;
// If not then proceed to copy the database from the application to the users filesystem
// Get the path to the database in the application package
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"test.sqlite"];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
2)Then talk to database in this way.
-(void)sqliteTransaction
{
sqlite3 *database;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:#"test.sqlite"];
// Init the animals Array
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "select * from me";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSLog(#"%#",aName);
// Create a new animal object with the data from the database
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
Try like this, before going to SELECT make sure the table is properly connected for selection with the open query like this
sqlite3_open(dbpath, &ProDB)
After that execute your selection. See this below sample code. Hope it will help
ex:
NSMutableArray *sessionDetails = [NSMutableArray array];
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"cPro.db"]];
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &ProDB) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat: #"SELECT * FROM USER_SESSION_INFO"];
NSLog(#"query: %#",querySQL);
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(ProDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
// Your functionality.
}
}
}
i tried the method you guys suggested but i still get the same problem.
i think i found out what's causing it.
i changed my query with this:
const char *sql = "SELECT product.ID,product.Name, product.details,product.price, product.quantityOnHand,product.image FROM Product";
and this way it works... so it looks like i have trouble reading other tables...
the moment i add another table it stop working. but that's weird cause with external db manager software the query works just fine

How to recieve data of a group by sqlite query in iOS ?

I want to get data of my group by query and load them into textfields.
here is my table
integer ID
Name text
Duration Real
Time Real
there are few names in in Name column
I tried calling method for each name , but it caused insert failure.
I want receive this query and load the result on specific Label: i dont know how can get the response
SELECT Name,SUM (time) FROM cost GROUP BY Name;
there is my current code
NSString *docsDir;
NSArray *dirPaths;
double totaltime = 1.0;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
// Build the path to the database file
databasePath = [[NSString alloc]
initWithString: [docsDir stringByAppendingPathComponent:
#"Database.db"]];
NSString *queryString=#"SELECT SUM(DURATION) AS TOTAL FROM RECORDS";
sqlite3_stmt *statement;
if(sqlite3_open([databasePath UTF8String], &myDatabase) == SQLITE_OK) {
if(sqlite3_prepare_v2(myDatabase, [queryString UTF8String], -1, &statement, nil) == SQLITE_OK){
while (sqlite3_step(statement) == SQLITE_ROW) {
totaltime = sqlite3_column_double(statement, 0);
NSLog(#"The sum is %f ", totaltime);
}
}
}
integer_t intotal=totaltime;
NSString* total=[NSString stringWithFormat:#"%d min",intotal];
totaltimefield.text=total;
This is all covered pretty nicely in the documentation, but, in short, once you update your SQL to have two columns:
const unsigned char* name = sqlite3_column_text(statement, 0);
double totaltime = sqlite3_column_double(statement, 1);
NSLog(#"The sum for %s is %f ", name, totaltime);
The second parameter int the sqlite3_column_x functions is the column number.

Resources