iOS SQLite Sum and retrieve data - iphone

I have a SQLite database that I am creating in my iOS application. A series of numbers are being stored in this database. I want to sum the entire column, and return the data to be displayed within the application.
Everything writing to the DB is working properly, but I am stuck trying to return the summed data. Any help would be greatly appreciated.
-(void) dataReturn: (NSString *) tableNamed{
NSString *myData = [NSString stringWithFormat:#"SELECT SUM(column1) AS data1 FROM myDB", tableNamed];
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(db, [myData UTF8String], -1, &statement, nil) ==SQLITE_OK){
while (sqlite3_step(statement) == SQLITE_ROW){
int *field2 = (int *) sqlite3_column_int(statement, 1);
NSString *myString =[[NSString alloc] initWithFormat:#"%#", field2];
}
}
}

Hello Nathan making a call as
[self dataReturn:#"Bill"];
to function
-(void)dataReturn:(NSString *)tableName{
sqlite3 *database;
sqlite3_stmt *statement;
NSString *queryString = [NSString stringWithFormat:#"SELECT SUM(price) AS TOTAL FROM %#", tableName];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
if(sqlite3_prepare_v2(database, [queryString UTF8String], -1, &statement, nil) == SQLITE_OK){
while (sqlite3_step(statement) == SQLITE_ROW) {
int field1 = sqlite3_column_int(statement, 0);
NSLog(#"The sum is %d ", field1);
}
}
}
}
will Fetch you desired data. The schema for Table "Bill" is "CREATE TABLE Bill (price double,quantity INTEGER)". The result fetched will have columns indexed from "0" so we pass 0 for first column. Hope you can take some hint from it. Cheers!!
int field1 = sqlite3_column_int(statement, 0);

From the sqlite3_column_int docs:
The leftmost column of the result set has the index 0.
Additionally, that function returns an int, not an int*. Try:
int field2 = sqlite3_column_int(statement, 0);

Related

not getting inside while loop when selecting a single row from sqlite

I have a problem with sqlite, when i select a single row from table and then check sqlite3_step(statement) == SQLITE_ROW both values are different and not getting inside while statement.
This is the code:
if (sqlite3_prepare_v2(db, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
//NSLog(#"working777.............%d",sqlite3_step(statement));
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"working888.............%d",SQLITE_ROW);
NSString *addressField = [[NSString alloc] initWithUTF8String: (const char *) sqlite3_column_text(statement, 0)];
NSString *phoneField = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 1)];
NSLog(#"............statement...........addressField %#, phoneField %#",addressField,phoneField);
}
sqlite3_finalize(statement);
}
sqlite3_close(db);
}
The proper way to create such a query would be like this:
NSString *querySQL = #"SELECT * FROM Major_Events WHERE temple_id = ?";
Then prepare the statement. I assume query_stmt is the char * value from querySQL.
Once the statement is prepared you then need to bind the value.
sqlite3_bind_int(statement, 1, temp_id); // bind is 1-based
Of course temp_id needs to be an int value and not a string. There are various sqlite3_bind_xxx statements for different data types. Use the appropriate one.
Once all of the query parameters are bound, you can execute the query using sqlite3_step.
The nice thing about this approach over string formats is that strings get properly escape and put in quotes for you. It's much harder to mess up and it makes your queries much safer against SQL injection attacks.
For many records:-
if (sqlite3_open([[self getDBPath] UTF8String], &database) == SQLITE_OK) {
const char *sql = "select * from Place";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
}
sqlite3_finalize(selectstmt);
sqlite3_close(database);
}
}
else
{
sqlite3_close(database);
}
If you want a single record then change while to if
if(sqlite3_step(selectstmt) == SQLITE_ROW) {
rest everything will be same
I hope it helps and if your while loop is not getting executed then it means there is some problem with your query.You need to check that also.

Performance issue in iOS-5 for Sqlite

I am facing one problem while using sqlite in iOS 5. I am fetching records from two tables: one in Recipe & other in Ingredients from one Menu.db
From Recipe table I get all record and one recipeid on that basis I fetch records from ingredients table. It takes no time to fetch record when run on iOS 4.2 but when I run on iOS 5 it takes time to fetch the records. See the following code:
NSString *query = [NSString stringWithFormat:#"select id from Recipes"];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
rcp.recipeID = sqlite3_column_int(selectstmt, 0);
NSString *sql = [NSString stringWithFormat:#"select Name from Ingredients where recipeId = %d",rcp.recipeID];
sqlite3_stmt *stmt2;
if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt2, NULL) == SQLITE_OK) {
while(sqlite3_step(stmt2) == SQLITE_ROW) {}
}
}
}
Why is this issue coming in iOS 5.0, the same code runs fine on iOS 4.0, 4.2?
I know, code I have written is right,I want to know the exact reason behind this Performance issue in iOS 5.0 for Sqlite bcoz my app is totally build around database.
Try with using two different functions
After you finish with complete execution of your first query, start with second query.
For example :-
NSString *query = [NSString stringWithFormat:#"select id from Recipes"];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
rcp.recipeID = sqlite3_column_int(selectstmt, 0);
}
}
and then call
NSString *sql = [NSString stringWithFormat:#"select Name from Ingredients where recipeId = %d",rcp.recipeID];
sqlite3_stmt *stmt2;
if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt2, NULL) == SQLITE_OK) {
while(sqlite3_step(stmt2) == SQLITE_ROW) {}
Hope this helps to solve your issue.
I think you linked against libsqlite3.dylib. You should link the libsqlite3.0.dylib library instead.
If you want contever your .db to .sqlite
open your .db file select the table File-> Export--> Table from CSV (save your file with .csv format)
(like this way you select all table)
then open .sqlite file
File-> Import--> Table from CSV
after your .csv file choose a dialog box appear
in that Extract field names from first line must tick marked
now your sqlite file is ready.
put this file into your project
then set your .sqlite/.db file path
now set your select query as like this
#import <sqlite3.h>
-(void)SelectSqlData:(NSString *)SearchString
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"yourfileName.sqlite"];
sqlite3_stmt *compiledStatement;
sqlite3 *database;
if(sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement;
sqlStatement = "select c.field1,c.field2,c.field3,c.field4 from YourTableName1 as c, YourTableName2 as b where b.Artist_Id = ?";
sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL);
//printf("\nError===%s",sqlite3_errmsg(database));
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_bind_text(compiledStatement,1,[SearchString UTF8String] , -1,SQLITE_STATIC);
while(sqlite3_step(compiledStatement) == SQLITE_ROW )
{
NSString *str_field1=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
NSString *str_field2=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *str_field3=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *str_field4=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
// add str_field into array
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
This probably isn't the answer you're looking for, but here's a small tip to improve performance.
NSString *query = [NSString stringWithFormat:#"select id from Recipes"];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
rcp.recipeID = sqlite3_column_int(selectstmt, 0);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//NSString *sql = [NSString stringWithFormat:#"select Name from Ingredients where recipeId = %d",rcp.recipeID];//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
sqlite3_stmt *stmt2;
if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt2, NULL) == SQLITE_OK) {
while(sqlite3_step(stmt2) == SQLITE_ROW) {}
}
}
}
Every iteration of the while loop, you create a new NSString object (NSString *sql = ...), so maybe you should instead do this:
NSString *query = [NSString stringWithFormat:#"select id from Recipes"];
NSString *sql = [NSString stringWithFormat:#"select Name from Ingredients where recipeId = %d",rcp.recipeID];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
rcp.recipeID = sqlite3_column_int(selectstmt, 0);
sqlite3_stmt *stmt2;
if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt2, NULL) == SQLITE_OK) {
while(sqlite3_step(stmt2) == SQLITE_ROW) {}
}
}
}
Hope this helps a bit!
The function GetListBySQL is optimized and iOS versions independent. May it will help you out.
-(NSMutableArray*)GetListBySQL:(NSString*)SQL
{
NSMutableArray* Array;
Array=[[NSMutableArray alloc]init];
NSStringEncoding enc = [NSString defaultCStringEncoding];
sqlite3_stmt *select_statement=nil;
if (sqlite3_prepare_v2(database, [SQL UTF8String], -1, &select_statement, NULL) != SQLITE_OK) {
NSString *errString = [NSString stringWithFormat:#"%#", [#"Fail" stringByReplacingOccurrencesOfString:#"#" withString:[NSString stringWithCString:sqlite3_errmsg(database) encoding:enc] ]];
NSAssert1(0, #"%#", errString);
}
int columncount=sqlite3_column_count(select_statement);
NSMutableDictionary* dic;
while (sqlite3_step(select_statement) == SQLITE_ROW)
{
dic=[[NSMutableDictionary alloc]init];
for(int j=0;j<columncount;j++)
{
if(sqlite3_column_text(select_statement, j)!=nil)
[dic setObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(select_statement, j)] forKey:[NSString stringWithUTF8String:(char *)sqlite3_column_name(select_statement,j)]];
else
[dic setObject:#"" forKey:[NSString stringWithUTF8String:(char *)sqlite3_column_name(select_statement,j)]];
}
[Array addObject:dic];
[dic release];
}
sqlite3_finalize(select_statement);
NSMutableArray *arr = [[NSMutableArray alloc] initWithArray: Array];
[Array release];
return arr;
}
Another alternative is to change SQLite to a Key/Value database like LevelDB (from google) or TokyoCabinet. I'm using LevelDB for two project right now and is working really good, and I used TokyoCabinet in the past also, the problem with TokyoCabinet is that is LGPL, so I'm not sure if is fully compatible with the iOS environment, but anyway I had several Apps in the appstore using Tokyo Cabinet (don't tell Apple).
For using both of them you will need a wrapper (Or maybe you can develop your own). This is a quick comparison and the available wrappers:
LevelDB: It seems to be one of the fastest out there (if not the fastest, take a look at their benchmarks). And as wrapper I'm currently using NULevelDB, if you have any problems adding it to your project let me know (I had some).
TokyoCabinet: It seems to be no so fast as LevelDB (I haven't run tests, I dropped it because of the license problems), but in the official page they recommend using their new library called KyotoCabinet that I haven't tested yet but is supposed to be faster. The wrapper I used was made by the amazing Aaron Hillegass, and it is called BNRPersistence.
As a recommendation, give a try to LevelDB, there is a bigger community behind, and the wrapper (NULevelDB) is simple and friendly.
Good luck!

BAD_ACCESS on SQLITE selection

I am getting EXC_BAD_ACCESS when I attempt to do anything with the value I'm selecting from the local SQLITE database on an iPhone development. The code for my function is
-(void) updateFromDB {
// Setup the database object
sqlite3 *database;
// Open DB
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSString *query = [NSString stringWithFormat:#"SELECT MOD_ID FROM MODULE;"];
//NSLog(#"QUERY: %#",query);
// Prepare statement
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) {
// Execute SQL
while (sqlite3_step(statement) == SQLITE_ROW) {
// Get MOD_IDs
NSInteger MOD_ID = sqlite3_column_int(statement, 0);
NSString *ID = [NSString stringWithFormat:#"%#",MOD_ID];
//=======================
// Get Notice Module Data
//=======================
if (MOD_ID == 1) {
self.noticeModule = [[ModuleSetting alloc] initWithID:ID];
}
}
} else {
NSAssert1(0,#"Error: failed to prepare statement. '%s'", sqlite3_errmsg(database));
}
// Release the compiled statement from memory
sqlite3_finalize(statement);
} else {
sqlite3_close(database);
NSAssert1(0,#"Failed to open database. '%s'",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
The bad access occurs on the line
NSString *ID = [NSString stringWithFormat:#"%#",MOD_ID];
Thanks for any help you can offer!
%# denotes objects. But MOD_ID seems to be an integer. So your format should be %d,
NSString *ID = [NSString stringWithFormat:#"%d", MOD_ID];
You can't use %# in format strings for integers, only for Obj-C objects. For integers, use %d (or for NSInteger, I think it is recommended to use %ld).
Have a look at the String Format Specifiers guide.
MOD_ID is not a pointer, so %# isn't correct.
Use below
NSInteger MOD_ID = sqlite3_column_int(statement, 0);
NSString *ID = [NSString stringWithFormat:#"%d",MOD_ID];

SQLite3 COUNT incorrect

Say i've got a table called Incidents, and a table called Devices.
Each device has a CI-code.
I want to create a tableView, with in the sections the names of the devices (CI), and each row to represent an incident.
To get the correct number of rows under each section, I use the following code:
NSMutableArray *lijstDevices = [[NSMutableArray alloc] init];
const char *dbpath = [appDelegate.databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat:#"SELECT DISTINCT CI FROM Devices"];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(contactDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
// NSLog(#"SQLite ROW for filling in cell");
NSString *addDev = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 0)];
[lijstDevices addObject:addDev];
}
sqlite3_finalize(statement);
}
NSString *ciNaam = [lijstDevices objectAtIndex:section];
NSString *querySQL2 = [NSString stringWithFormat:#"SELECT COUNT(ID) FROM Incidents WHERE CI='%#'", ciNaam];
const char *query_stmt2 = [querySQL2 UTF8String];
if (sqlite3_prepare_v2(contactDB, query_stmt2, -1, &statement, NULL) == SQLITE_OK)
{
//NSLog(#"SQLite ok in rowforindexpath");
if(sqlite3_step(statement) == SQLITE_ROW) {
// NSLog(#"SQLite ROW for filling in cell");
teller = sqlite3_column_int(statement, 0);
}
else
{
NSLog(#"Not.. good...");
}
sqlite3_finalize(statement);
}
sqlite3_close(contactDB);
}
Here comes the problem: The sections are filled correctly. Some sections need 1 row, other sections need 2 rows. Whenever I run the program, each section which needs 1 row ends up with 0 rows, while each section with 2 rows needed end up with only 1 row.
Besides that, I had an error before which didn't clean the tables. Therefore, if I ran it twice, the database got doubled up on rows. In that case, each one which needed 1, has 2 rows. Each one which needed 2, had 4 rows. This is obviously not the case anymore but it might help understanding what's wrong.
Anyone having any idea???
u see this example and check it
-(void)ChekInDataBase{
sqlite3 *database;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSString *sqlStatement = [NSString stringWithFormat:#"SELECT count(id) as countRow FROM password"];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, [sqlStatement cStringUsingEncoding:NSUTF8StringEncoding], -1, &compiledStatement, NULL) == SQLITE_OK)
{
NSLog(#"%#",sqlStatement);
if (sqlite3_step(compiledStatement) == SQLITE_ROW)
{
countRow = [[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement,0 )]intValue] ;
}
}
sqlite3_finalize(compiledStatement);
if (countRow > 0)
{
[yesBtnPressed setImage:[UIImage imageNamed:#"yes_tab_over.png"]forState:UIControlStateNormal];
[noBtnPressed setImage:[UIImage imageNamed:#"no_tab.png"]forState:UIControlStateNormal];
[noBtnPressed setUserInteractionEnabled:TRUE];
[yesBtnPressed setUserInteractionEnabled:FALSE];
}
else
{
[yesBtnPressed setImage:[UIImage imageNamed:#"yes_tab.png"]forState:UIControlStateNormal];
[noBtnPressed setImage:[UIImage imageNamed:#"no_tab_over.png"]forState:UIControlStateNormal];
[noBtnPressed setUserInteractionEnabled:FALSE];
[yesBtnPressed setUserInteractionEnabled:TRUE];
}
sqlite3_close(database);
}
}
There was no error in this line. Apparently, the CI-code didn't get added in the table correctly. Sometimes it shows the CI-code correct (the ones I can see in the list), but the others just have (null) or 1 as code.

Find Maximum Value in a column from sqlite database

I Am using following code for getting maximum value in column
Column no 11 (means 10 no, in the code)
Column Name uniqueColumnSNo
Data type of Column -integer.
I am confused with syntax used by dbhanlder.
Here is the code.
Just let me know , HOW I WILL ACHIEVE MAXIMUM VALUE TO BE RETURNED from the specified column.
Help. Thanks in Advance.
+(int)getMaxColumnSNo
{
NSInteger favid;
int count=0;
sqlite3 *database;
NSString *dbpath;
dbpath = [dbhandler dataFilePath:DbName];
if (sqlite3_open([dbpath UTF8String], &database) == SQLITE_OK)
{
NSString *selectSql = [NSString stringWithFormat:#"SELECT max(uniqueColumnSNo) FROM CustomerFields"];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [selectSql cStringUsingEncoding:NSUTF8StringEncoding], -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
//[result addObject:[[NSMutableDictionary alloc] init]];
favid=(NSInteger)sqlite3_column_int64(statement,10);
//favid = [[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 10)] intValue];
count++;
}
sqlite3_finalize(statement);
}
else
{
NSLog(#"Sql Preparing Error");
}
sqlite3_close(database);
}
else
{
NSLog(#"Database not opening");
}
int i;
if (count!=0) {
i=favid ;
}
else {
i=1;
}
return i;
//return favid;
}
You need:
sqlite3_column_int64( statement, 0 );
The column number parameter is the index of the result set, not of the original table column number. Your only column in the result set is max(uniqueColumnSNo), thus this is column index number 0.