Android SQLite crashed after 170 row - android

how to change this logic to work with more than 170 rows.
// Getting All test
public List<Test> getAllTests(String str) {
List<Test> testList = new ArrayList<Test>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_TESTS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
//select rows by input string
if(cursor.getString(1).equals(str)){
Test test = new Test();
test.setId(Integer.parseInt(cursor.getString(0)));
test.setTest(cursor.getString(1));
test .setResult(Integer.parseInt(cursor.getString(2)));
// Adding test to list
testList.add(test);
}
} while (cursor.moveToNext());
}
//close database
db.close();
//return list data
return testList;
}
I want to select all rows by input string. It logic work perfectly with 150 rows but after 160 work slowly and crash on 170 rows

how to change this logic to work with more than 170 rows?
// Getting All test
public List<Test> getAllTests(String str) {
List<Test> testList = new ArrayList<Test>();
// Select All Query
//String selectQuery = "SELECT * FROM " + TABLE_TESTS;
String selectQuery = "SELECT id,result FROM " + TABLE_TESTS + " where name ='" + str + "'";
// Now you are saving memory of one column.
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
Test test = new Test();
// moved outside loop to prevent creating new object every time.
do {
//select rows by input string
//if(cursor.getString(1).equals(str)){
// No need for if Codition any more
test.setId(Integer.parseInt(cursor.getString(0)));
//test.setTest(cursor.getString(1));
test.setTest(str);
test .setResult(Integer.parseInt(cursor.getString(2)));
// Adding test to list
testList.add(test);
//}
} while (cursor.moveToNext());
}
//close database
db.close();
//return list data
return testList;
}

EDITED: MISPELLED METHOD
Use
String selectQuery = "SELECT * FROM " + TABLE_TESTS + " WHERE " + your_id + " > " + String.valueOf(last_id) + " LIMIT 150";
as your query structure, and then keep track of the last row id like this`
int last_id;
do {
//select rows by input string
if(cursor.getString(1).equals(str)){
Test test = new Test();
last_id = Integer.parseInt(cursor.getString(0));
test.setId(last_id);
...
}
} while (cursor.moveToNext());
every time the loop ends, just query again your db; the rows will be fetched from the next one you need, because last_id variable dinamically change according to your progress.

Could try using same code differently in following way
// using sql query Differently
(SQliteDatabase) db.query(
"TABLE_TESTS" / table name /,
new String[] { "id", "result" } / columns names /,
"name = ?" / where or selection /,
new String[] { str } / selectionArgs i.e. value to replace ? /,
null / groupBy /,
null / having /,
null / orderBy /
);
Another approach could be to use LIMIT and OFFSET to get data in parts to improve performance
// using LIMIT AND OFFSET
public List<Test> getAllTests(String str) {
List<Test> testList = new ArrayList<Test>();
// Select All Query
Integer count = 0;
String countQuery = "SELECT count(id) FROM " + TABLE_TESTS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
if (cursor.moveToFirst()) {
count= c.getCount();
}
db.close();
int MAX_LENGTH = 150;
if ( count > 0 ) {
int total_length = ( count / MAX_LENGTH ) + 1;
for ( int i=0; i<total_length; i++) {
String selectQuery = "SELECT id,result FROM " + TABLE_TESTS + " LIMIT " + MAX_LENGTH + " OFFSET " + (i*MAX_LENGTH) ;
db = this.getWritableDatabase();
cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
Test test = new Test();
// moved outside loop to prevent creating new object every time.
do {
//select rows by input string
if(cursor.getString(1).equals(str)){
test.setId(Integer.parseInt(cursor.getString(0)));
//test.setTest(cursor.getString(1));
test.setTest(str);
test .setResult(Integer.parseInt(cursor.getString(2)));
// Adding test to list
testList.add(test);
}
} while (cursor.moveToNext());
}
//close database
db.close();
}
}
//return list data
return testList;
}

Related

Double values for selected contact android

I have a List of contacts with check box.When the user checks the check box i have updated my table field selectedValue with value=1 .Now what i want is i wamna get all the contacts in comma seperated way where selectedValue=1.So for that i have written a query.But my result is not desired.
For eg
I have 4 contacts A,B,C,D in a list.Now if user selects A and C from the list and when i fire that query to get the contacs comma seperated,this is what i get
A,A,C,C
I dont know why 2 values of A and C are comming
Code
public StringBuilder getCheckedContact() {
database = getWritableDatabase();
StringBuilder values = new StringBuilder();
String query = "Select * From " + contactTable + " where " + selectedContact + "=1";
Cursor c = database.rawQuery(query, null);
while (c.moveToNext()) {
for (int i = 0; i < c.getCount(); i++) {
values.append(c.getString(c.getColumnIndexOrThrow(contactName)));
if (i != c.getCount() - 1) {
values.append(",");
}
}
}
c.close();
database.close();
return values;
}
Your while loop loops over the results once, then the for loop loops over the results second time. If you select 4 contacts, you'd get 4*4=16 results.
Why did you add the inner for loop?
This could be rewritten as follows:
public StringBuilder getCheckedContact() {
database = getWritableDatabase();
StringBuilder values = new StringBuilder();
String query = "Select * From " + contactTable + " where " + selectedContact + "=1";
Cursor c = database.rawQuery(query, null);
boolean firstItem = true;
while (c.moveToNext()) {
if(firstItem)
firstItem = false;
else
values.append(",");
values.append(c.getString(c.getColumnIndexOrThrow(contactName)));
}
c.close();
database.close();
return values;
}

Android SQLite incrementing a column value

I'm trying to create a score database that increments the players 'score' by one when they win by calling updateScore(). The primary key and player number are identical (I may need to restructure the DB at some point) and the final column is 'score'.
Below is the code that initially sets the score (this works), the method that gets the score (also works fine) and the method that updates the score, incrementing the relevant players score by 1. This is the part the doesn't work, is there something I should be doing differently here? Thanks.
/** Add a record to the database of two player scores
* #param playerId
* #param playerScore
**/
public void addScore (int playerId, int playerScore) {
SQLiteDatabase database = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(ID, playerId);
values.put(PLAYERNUM, playerId);
values.put(SCORE, playerScore);
database.insert(TABLE_2PSCORES, null, values);
database.close();
}
// Get the score
public int getScore (int playerId) {
SQLiteDatabase database = this.getReadableDatabase();
Cursor cursor = database.query(TABLE_2PSCORES, COLUMNS, " player = ?", new String[] {String.valueOf(playerId) }, null, null, null, null); //null = groupby, having, orderby, limit
if (cursor !=null) { cursor.moveToFirst(); }
int output = cursor.getInt(2);
return output;
}
// Increment score by 1
public void updateScore (int playerId) {
SQLiteDatabase database = this.getWritableDatabase();
int playerScore = getScore(playerId);
int playerScoreInc = playerScore ++;
ContentValues values = new ContentValues();
values.put("score", playerScoreInc);
database.update(TABLE_2PSCORES, values, PLAYERNUM+" = ?", new String[] {String.valueOf(playerId)} );
database.close();
}
int playerScoreInc = playerScore ++;
This assigns playerScore to playerScoreInc and only after that increments playerScore. To first increment and then assign, change to ++playerScore.
However, you can do it all in SQL, no need to fetch score, increment it in code and then update the database table separately:
database.execSQL("UPDATE " + TABLE_2PSCORES + " SET " + SCORE + "=" + SCORE + "+1" + " WHERE " + PLAYERNUM + "=?",
new String[] { String.valueOf(playerId) } );
The other answers solve the original question, but the syntax makes it hard to understand. This is a more general answer for future viewers.
How to increment a SQLite column value
SQLite
The general SQLite syntax is
UPDATE {Table} SET {Column} = {Column} + {Value} WHERE {Condition}
An example of this is
UPDATE Products SET Price = Price + 1 WHERE ProductID = 50
(Credits to this answer)
Android
Now that the general syntax is clear, let me translate that into Android syntax.
private static final String PRODUCTS_TABLE = "Products";
private static final String ID = "ProductID";
private static final String PRICE = "Price";
String valueToIncrementBy = "1";
String productId = "50";
String[] bindingArgs = new String[]{ valueToIncrementBy, productId };
SQLiteDatabase db = helper.getWritableDatabase();
db.execSQL("UPDATE " + PRODUCTS_TABLE +
" SET " + PRICE + " = " + PRICE + " + ?" +
" WHERE " + ID + " = ?",
bindingArgs);
db.close();
TODO
This answer should be updated to use update rather than execSQL. See comment below.
Change
int playerScoreInc = playerScore ++;
to
int playerScoreInc = ++ playerScore;
I think this will work
// Increment score by 1
public void updateScore (int playerId) {
SQLiteDatabase database = this.getWritableDatabase();
int playerScore = getScore(playerId);
int playerScoreInc = ++ playerScore;
ContentValues values = new ContentValues();
values.put("score", playerScoreInc);
database.update(TABLE_2PSCORES, values, PLAYERNUM+" = ?", new String[] {String.valueOf(playerId)} );
database.close();
}
Have you tried debugging? Try debugging this line:
int playerScoreInc = playerScore ++;
The playerScoreInc doesn't increment.

Getting value from table that is empty in sqlite android-Showing Null Pointer Exception

I'd like to get a value from a table. If the column does not contain any value, then I am going to insert one.
If there is a value, I want to notify the user that a value was inserted already. When my table does not contain anything it shows an error as Java Null Pointer Exception. I want to get a null value from my table. Please help.
String qu="select * from userinfos";
c=db.rawQuery(qu,null);
int count = c.getCount();
String[] values = new String[count + 1];
int i = 0;
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
values[i] = c.getString(c.getColumnIndex("mail"));
Toast.makeText(FiveActivity.this, values[i],Toast.LENGTH_LONG).show();
i++;
}
i=0;
if(values[i].equals(null))
{
String Query = "insert into userinfos (mail,pass) values ('"+ mailuser+ "','" + password + "')";
db.execSQL(Query);
Toast.makeText(FiveActivity.this,"Values Inserted",Toast.LENGTH_LONG).show();
}
else
{
for(int j=0;j<3;j++)
Toast.makeText(FiveActivity.this,"Already one Email-Id:"+ values[i]+" "+"you given. if you want to insert new mail and password then go to Delete app",Toast.LENGTH_LONG).show();
}
You just need to check your count value like below:
c=db.rawQuery(qu,null);
int count = c.getCount();
if(count==0)
{
////// No data found
}
else
{
/////data available
}
getCount ()
Returns the numbers of rows in the cursor
http://developer.android.com/reference/android/database/Cursor.html#getCount
this is a simple fonction to manage Usertable or others:
/**
* Check if data exist in table
*
* #param table
* The table to check data
* #param whereArgs
* The conditions to check the data
* #return boolean Return True while data exist; False while data not exist
*/
public boolean isDataExist(String table, String column, String[] whereArgs) {
boolean result = false;
SQLiteDatabase db = this.getWritableDatabase();
String sql = "select * from " + table + " where " + column + " = ?";
Cursor cursor = db.rawQuery(sql, whereArgs);
if (cursor.getCount() > 0) {
result = true;
}
cursor.close();
db.close();
return result;
}

Android: Get entire column data

Im trying to get the data of an entire column into a string array. My database contains two columns Id and Names. I want to read all the entries of the names column and put it into a array. Please help.
EDIT #1:
Im using the following code but i can get only one name with this code.
String query = "Select * FROM " + TABLE_APPS + " WHERE " + COLUMN_NAME + " = \"" + productname + "\"";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
if (cursor.moveToFirst()) {
cursor.moveToFirst();
name = cursor.getString(1);
cursor.close();
} else {
name = null;
}
db.close();
int total=0;
Cursor csr=sdb.query("tablename", null, null,null,null,null,null);
csr.moveToFirst();
while(!csr.isAfterLast())
{
total++;
csr.moveToNext();
}
String strarray[] = new String[total];
Cursor csrs=sdb.query("tablename", null, null,null,null,null,null);
csrs.moveToFirst();
int aray=0;
while(!csrs.isAfterLast())
{
strarray[aray]=csrs.getString(1);
aray++;
csrs.moveToNext();
}

IN clause and placeholders

I'm attempting to do the following SQL query within Android:
String names = "'name1', 'name2"; // in the code this is dynamically generated
String query = "SELECT * FROM table WHERE name IN (?)";
Cursor cursor = mDb.rawQuery(query, new String[]{names});
However, Android does not replace the question mark with the correct values. I could do the following, however, this does not protect against SQL injection:
String query = "SELECT * FROM table WHERE name IN (" + names + ")";
Cursor cursor = mDb.rawQuery(query, null);
How can I get around this issue and be able to use the IN clause?
A string of the form "?, ?, ..., ?" can be a dynamically created string and safely put into the original SQL query (because it is a restricted form that does not contain external data) and then the placeholders can be used as normal.
Consider a function String makePlaceholders(int len) which returns len question-marks separated with commas, then:
String[] names = { "name1", "name2" }; // do whatever is needed first
String query = "SELECT * FROM table"
+ " WHERE name IN (" + makePlaceholders(names.length) + ")";
Cursor cursor = mDb.rawQuery(query, names);
Just make sure to pass exactly as many values as places. The default maximum limit of host parameters in SQLite is 999 - at least in a normal build, not sure about Android :)
Here is one implementation:
String makePlaceholders(int len) {
if (len < 1) {
// It will lead to an invalid query anyway ..
throw new RuntimeException("No placeholders");
} else {
StringBuilder sb = new StringBuilder(len * 2 - 1);
sb.append("?");
for (int i = 1; i < len; i++) {
sb.append(",?");
}
return sb.toString();
}
}
Short example, based on answer of user166390:
public Cursor selectRowsByCodes(String[] codes) {
try {
SQLiteDatabase db = getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String[] sqlSelect = {COLUMN_NAME_ID, COLUMN_NAME_CODE, COLUMN_NAME_NAME, COLUMN_NAME_PURPOSE, COLUMN_NAME_STATUS};
String sqlTables = "Enumbers";
qb.setTables(sqlTables);
Cursor c = qb.query(db, sqlSelect, COLUMN_NAME_CODE+" IN (" +
TextUtils.join(",", Collections.nCopies(codes.length, "?")) +
")", codes,
null, null, null);
c.moveToFirst();
return c;
} catch (Exception e) {
Log.e(this.getClass().getCanonicalName(), e.getMessage() + e.getStackTrace().toString());
}
return null;
}
Sadly there's no way of doing that (obviously 'name1', 'name2' is not a single value and can therefore not be used in a prepared statement).
So you will have to lower your sights (e.g. by creating very specific, not reusable queries like WHERE name IN (?, ?, ?)) or not using stored procedures and try to prevent SQL injections with some other techniques...
As suggest in accepted answer but without using custom function to generate comma-separated '?'. Please check code below.
String[] names = { "name1", "name2" }; // do whatever is needed first
String query = "SELECT * FROM table"
+ " WHERE name IN (" + TextUtils.join(",", Collections.nCopies(names.length, "?")) + ")";
Cursor cursor = mDb.rawQuery(query, names);
You can use TextUtils.join(",", parameters) to take advantage of sqlite binding parameters, where parameters is a list with "?" placeholders and the result string is something like "?,?,..,?".
Here is a little example:
Set<Integer> positionsSet = membersListCursorAdapter.getCurrentCheckedPosition();
List<String> ids = new ArrayList<>();
List<String> parameters = new ArrayList<>();
for (Integer position : positionsSet) {
ids.add(String.valueOf(membersListCursorAdapter.getItemId(position)));
parameters.add("?");
}
getActivity().getContentResolver().delete(
SharedUserTable.CONTENT_URI,
SharedUserTable._ID + " in (" + TextUtils.join(",", parameters) + ")",
ids.toArray(new String[ids.size()])
);
Actually you could use android's native way of querying instead of rawQuery:
public int updateContactsByServerIds(ArrayList<Integer> serverIds, final long groupId) {
final int serverIdsCount = serverIds.size()-1; // 0 for one and only id, -1 if empty list
final StringBuilder ids = new StringBuilder("");
if (serverIdsCount>0) // ambiguous "if" but -1 leads to endless cycle
for (int i = 0; i < serverIdsCount; i++)
ids.append(String.valueOf(serverIds.get(i))).append(",");
// add last (or one and only) id without comma
ids.append(String.valueOf(serverIds.get(serverIdsCount))); //-1 throws exception
// remove last comma
Log.i(this,"whereIdsList: "+ids);
final String whereClause = Tables.Contacts.USER_ID + " IN ("+ids+")";
final ContentValues args = new ContentValues();
args.put(Tables.Contacts.GROUP_ID, groupId);
int numberOfRowsAffected = 0;
SQLiteDatabase db = dbAdapter.getWritableDatabase());
try {
numberOfRowsAffected = db.update(Tables.Contacts.TABLE_NAME, args, whereClause, null);
} catch (Exception e) {
e.printStackTrace();
}
dbAdapter.closeWritableDB();
Log.d(TAG, "updateContactsByServerIds() numberOfRowsAffected: " + numberOfRowsAffected);
return numberOfRowsAffected;
}
This is not Valid
String subQuery = "SELECT _id FROM tnl_partofspeech where part_of_speech = 'noun'";
Cursor cursor = SQLDataBase.rawQuery(
"SELECT * FROM table_main where part_of_speech_id IN (" +
"?" +
")",
new String[]{subQuery}););
This is Valid
String subQuery = "SELECT _id FROM tbl_partofspeech where part_of_speech = 'noun'";
Cursor cursor = SQLDataBase.rawQuery(
"SELECT * FROM table_main where part_of_speech_id IN (" +
subQuery +
")",
null);
Using ContentResolver
String subQuery = "SELECT _id FROM tbl_partofspeech where part_of_speech = 'noun' ";
final String[] selectionArgs = new String[]{"1","2"};
final String selection = "_id IN ( ?,? )) AND part_of_speech_id IN (( " + subQuery + ") ";
SQLiteDatabase SQLDataBase = DataBaseManage.getReadableDatabase(this);
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables("tableName");
Cursor cursor = queryBuilder.query(SQLDataBase, null, selection, selectionArgs, null,
null, null);
In Kotlin you can use joinToString
val query = "SELECT * FROM table WHERE name IN (${names.joinToString(separator = ",") { "?" }})"
val cursor = mDb.rawQuery(query, names.toTypedArray())
I use the Stream API for this:
final String[] args = Stream.of("some","data","for","args").toArray(String[]::new);
final String placeholders = Stream.generate(() -> "?").limit(args.length).collect(Collectors.joining(","));
final String selection = String.format("SELECT * FROM table WHERE name IN(%s)", placeholders);
db.rawQuery(selection, args);

Categories

Resources