This is a simple method to randomly shuffle certain database table entries based on a specific column value. Thanks to cbrulak's help, it now functions appropriately. It is not the most efficient by any means, but I thought I would just post it after the fix, as someone may find it somewhat useful.
/* The method will shuffle the specific entries in the table, based on column value */
public void shuffleDeck(int deck_id){
int i, j, count;
int loop1, loop2;
int num;
int id1, id2;
Random rand = new Random();
String front1, back1, front2, back2;
/* Create two separate content values for swapping the values between the two rows */
ContentValues updated_1 = new ContentValues();
ContentValues updated_2 = new ContentValues();
String[] columns = new String[]{CARD_ROWID, CARD_FRONT, CARD_BACK};
/* Create two cursors pointing to the same query */
Cursor cursor1 = Database.query(CARDS_TABLE, columns, DECK_ROWID + " = " + deck_id,
null, null, null, null);
Cursor cursor2 = Database.query(CARDS_TABLE, columns, DECK_ROWID + " = " + deck_id,
null, null, null, null);
cursor1.moveToFirst();
cursor2.moveToFirst();
int iRow = cursor1.getColumnIndex(CARD_ROWID);
int iFront = cursor1.getColumnIndex(CARD_FRONT);
int iBack = cursor1.getColumnIndex(CARD_BACK);
/* Get total number of entries in the cursor */
count = cursor1.getCount();
/* Loop through */
for(i=1; i<=count; i++){
num = rand.nextInt(count) + 1;
/* Acquire the values from the current row that will be inserted into the randomly selected row */
id1 = cursor1.getInt(iRow);
front1 = cursor1.getString(iFront);
back1 = cursor1.getString(iBack);
/* Move to the next row in cursor2 for a random number of times */
for (j=1; j<num; j++){
cursor2.moveToNext();
/* Fail safe to make sure it doesn't go out of bounds */
if(cursor2.isLast())
break;
}
/* Acquire the values from the random row */
front2 = cursor2.getString(iFront);
back2 = cursor2.getString(iBack);
id2 = cursor2.getInt(iRow);
/* Check to see if the second cursor is also pointing to the same position. */
if(!(front1.equals(front2) && back1.equals(back2))){
updated_1.put(CARD_FRONT, front2);
updated_1.put(CARD_BACK, back2);
updated_2.put(CARD_FRONT, front1);
updated_2.put(CARD_BACK, back1);
/* Call the database to UPDATE the values */
Database.update(CARDS_TABLE, updated_1, CARD_ROWID + " = " + id1, null);
Database.update(CARDS_TABLE, updated_2, CARD_ROWID + " = " + id2, null);
/* Clear the content values */
updated_1.remove(CARD_FRONT);
updated_1.remove(CARD_BACK);
updated_2.remove(CARD_FRONT);
updated_2.remove(CARD_BACK);
/* Requery the cursors */
cursor1 = Database.query(CARDS_TABLE, columns, DECK_ROWID + " = " + deck_id,
null, null, null, null);
cursor2 = Database.query(CARDS_TABLE, columns, DECK_ROWID + " = " + deck_id,
null, null, null, null);
/* Move cursor1 to the same position it was, right before requerying it */
for(loop1 = 1; loop1<=i; loop1++){
cursor1.moveToNext();
/* Fail save in case it tries to go out of bound */
if(cursor1.isLast())
break;
}
/* Move cursor2 to the same position it was, right before requerying it */
for(loop2 = 1; loop2<=j; loop2++){
cursor2.moveToNext();
/* Fail save in case it tries to go out of bound */
if(cursor2.isLast())
break;
}
}
/* Move the cursors to the new positions */
cursor1.moveToNext();
cursor2.moveToFirst();
}
cursor1.close();
cursor2.close();
}
request a new cursor after the update(s).
See: Android - Can you update a Cursor for SQLite results?
And more important: http://developer.android.com/reference/android/database/Cursor.html#requery() (they say to request new ones)
Bonus points for you: use a content provider. Save you tons of headache.
Related
My android app has 2 tables Projects and Tasks.
Each Project can have multiple Tasks.
Like below
Now I want to sum up all proportion values of the single task table
I did it.. but the issue is its adding proportion values from all task tables !
The cursor I coded is as follows
public int sumproportion(long projectId){
int value = 0;
int p = 0;
Cursor cu = mDatabase.rawQuery("SELECT * FROM " + DBHelper.TABLE_TASKS, null);
ArrayList temp = new ArrayList();
if (cur != null) {
if (cur.moveToFirst()) {
do {
temp.add(cur.getString(cur.getColumnIndex("proportion"))); // "Title" is the field name(column) of the Table
} while (cur.moveToNext());
}
}
Object ia[] = temp.toArray();
for(int i=0; i<ia.length; i++)
{
p = Integer.parseInt((String) ia[i]);
value = value + p;
}
System.out.println("Value is: " + value);
return value;
}
When I added cursor as below
Cursor cur = mDatabase.query(DBHelper.TABLE_TASKS, mAllColumns,
DBHelper.COLUMN_TASK_PROJECT_ID + " ="+String.valueOf(projectId),
null, null, null, null);
It doesn't add anything. Can any one help fix it please?
First of all, you can just use query like this SELECT SUM(proportion) from TABLE_TASK. proportion should have numeric type.
Secondly, verify that your Cursor return any rows. Probably you pass wrong projectId if there no rows.
I'm trying to implement dynamic queries in my Android app, to let the users search according to some criteria. In this case I'm trying to search simply by an integer value. Here's my attempt:
...
public String[][] listarNegocio(int idProyecto,
int minimo,
int maximo)
{
String[][] arrayDatos = null;
String[] parametros = {String.valueOf(idProyecto)};
Cursor cursor = null;
cursor = querySQL("SELECT *" +
" FROM negocio" +
" WHERE ? in (0, id_proyecto)", parametros);
if(cursor.getCount() > 0)
{
int i = minimo - 1;
arrayDatos = new String[maximo - minimo + 1][20];
while(cursor.moveToNext() && i < maximo)
{
// Here I fill the array with data
i = i + 1;
}
}
cursor.close();
CloseDB();
return(arrayDatos);
}
public Cursor querySQL(String sql, String[] selectionArgs)
{
Cursor oRet = null;
// Opens the database object in "write" mode.
db = oDB.getReadableDatabase();
oRet = db.rawQuery(sql, selectionArgs);
return(oRet);
}
...
I tested this query using SQLFiddle, and it should return only the rows where the column id_proyecto equals the parameter idProyecto, or every row if idProyecto equals 0. But it doesn't return anything. If I remove the WHERE clause and replace "parametros" with "null", it works fine.
Additionally, I need to search by text values, using LIKE. For example, WHERE col_name LIKE strName + '%' OR strName = ''. How should I format my parameters and the query to make it work?
You should do one query for each case. For an id that exists, do SELECT * FROM negocio WHERE id_proyecto = ?. For an id that doesn't exist (I'm assuming 0 isn't a real id), just query everything with SELECT * FROM negocio.
Code should be something like this:
if(parametros[0] != 0){
cursor = querySQL("SELECT *" +
" FROM negocio" +
" WHERE id_proyecto = ?", parametros);
} else {
cursor = querySQL("SELECT *" +
" FROM negocio", null);
}
Regarding your second question, it depends on what you're looking for, you could use LIKE '%param%' or CONTAINS for occurrences in between text, LIKE param for partial matches or just = param if you're looking an exact match.
I am populating AChartEngine from sqlite database and I need all of the data to be displayed. The problem I'm having is when I delete a record the graph series stops populating at the deleted record. I need to find a way to skip over deleted/empty records and continue populating my graph. I need it to do it the same way listview skips over deleted records and keeps on displaying all rows. I am very new to a lot of this and am having a very difficult time with this. I have tried to write if statements in order to skip deleted/empty rows but nothing seems to work. Thank you for helping!
in my graphing activity:
for (int i = 1; !c.isAfterLast(); i++) {
String value1 = db.getValue1(i);
String value2 = db.getValue2(i);
c.moveToNext();
double x7 = Double.parseDouble(value1);
double y7 = Double.parseDouble(value2);
myseries.add(x7, y7);
}
I am getting error: CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
If I surround with try and catch it will populate rows up until the deleted record.
"EDIT"
in my sqlite database:
public String getValue1(long l) {
String[] columns = new String[]{ EMP_DEPT };
Cursor c = db.query(EMP_TABLE, columns, EMP_ID + "=" + l, null, null, null, null);
if (c != null){
c.moveToFirst();
String value1 = c.getString(0);
return value1;
}
return null;
}
public String getValue2(long l) {
String[] columns = new String[]{ EMP_DATE1 };
Cursor c = db.query(EMP_TABLE, columns, EMP_ID + "=" + l, null, null, null, null);
if (c != null){
c.moveToFirst();
String value2 = c.getString(0);
return value2;
}
return null;
}
Your issue is that your safety net for commands on rows that don't exist is to use if (c != null){ and then perform your commands inside that block, but a Cursor request from a query will never come up null, it will instead result in a cursor object with no rows.
A more appropriate solution to use this as your safety net instead if (c.moveToFirst()){ Because the method itself returns a boolean for if the method actually carried itself out in the first place - true if it moved and false if not (which occurs when there's no rows to move into). another check, if you wish, would be to see how many rows the cursor has with c.getCount().
Additionally, you should combine your methods so that you don't make redundant queries to the database:
public String[] getValues(long l) {
String[] results = new String[2];
String[] columns = new String[]{ EMP_DEPT, EMP_DATE1 };
Cursor c = db.query(EMP_TABLE, columns, EMP_ID + "=" + l, null, null, null, null);
if (c.moveToFirst()) {
results[0] = c.getString(0);
results[1] = c.getString(1);
} else {
Log.d("GET_VALUES", "No results formed from this query!");
}
return results;
}
You should use a single query to get all values at once:
SELECT Date1 FROM MyTable WHERE id BETWEEN 1 AND 12345
or:
db.query(EMP_TABLE, columns, EMP_ID + " BETWEEN 1 AND " + ..., ...);
Then missing values will just not show up when you iterate over the cursor.
I made a query that requests a random row from database using ID. But I have a little problem. I want it to show a message if it exists or it doesn't exist. For example my database like that:
ID - ingilizce - turkce
1 - hello - merhaba
4 - hi - selam
As you see, the second and third record don't exist. I generate a random number between 1 and 4 and I get the row that belongs to ID. So, when it generates a number like 2 or 3, it will generate a new random number.
My code is here:
public void kelimeUret() {
SQLiteDatabase db = kelimeler.getReadableDatabase();
rastgele = new Random();
Cursor kayit = db.rawQuery("SELECT count(*) FROM kelimeler", null);
kayit.moveToFirst();
int max = Integer.parseInt(kayit.getString(0));
int min = 1;
int rastgeleKayit = rastgele.nextInt(max - min + 1) + min;
Cursor kayit3 = db.rawQuery("SELECT * FROM kelimeler WHERE id=" + rastgeleKayit, null);
kayit3.moveToFirst();
int kayitSayisi = kayit3.getCount();
if (kayitSayisi<1) {
//Toast.makeText(getApplicationContext(), "bu kayıt yok", Toast.LENGTH_SHORT).show();
//kelimeUret();
// I COULDN'T DO HERE !
} else {
Cursor kayit2 = db.rawQuery("SELECT ingilizce FROM kelimeler WHERE id=" + rastgeleKayit, null);
kayit2.moveToFirst();
String sonuc = kayit2.getString(0);
olusturulanKelime = sonuc;
kelime = (TextView) findViewById(R.id.kelime);
kelime.setText(sonuc);
}
Thanks for your responds...
Cursor kayit3 = db.rawQuery("SELECT * FROM kelimeler WHERE id=" + rastgeleKayit, null);
kayit3.moveToFirst();
kayit3.getCount(); will return the number of records returned by the query. If there are no records, then it does not exist. If it returns more than 1 record, then the record exist.
Hope this helps
is there a way to change my function:
public categorie createCategoria(String categoria) {
ContentValues values = new ContentValues();
values.put(MySQLiteHelper.COLUMN_NOME, categoria);
values.put(MySQLiteHelper.COLUMN_PREF, 0);
long insertId = database.insert(MySQLiteHelper.TABLE_CATEGORIE, null,
values);
Cursor cursor = database.query(MySQLiteHelper.TABLE_CATEGORIE,
allCategorieColumns, MySQLiteHelper.COLUMN_ID + " = " + insertId, null,
null, null, null);
cursor.moveToFirst();
categorie newCategoria = cursorToCategorie(cursor);
cursor.close();
return newCategoria;
}
this is a raw insert, i would like to change this function to make it update or insert accordingly. i would like to change this becouse i'm already using this function in some places, but now i need to choose if insert a row or update (or ignoring the insert) a row with the same COLUMN_NOME. can someone help me doing this?
i mean i would like to insert a new row ONLY if there isn't another with the same name (as usual you know).
You can use insertWithOnConflict() if you want to insert or update, depending in whether the record exists or not:
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COLUMN_ID, id);
contentValues.put(COLUMN_VALUE, value);
// this will insert if record is new, update otherwise
db.insertWithOnConflict(TABLE, null, contentValues, SQLiteDatabase.CONFLICT_REPLACE);
you could call int nRowsEffected = database.update(...); if there are no rows effected by the update either the row doesn't exist (or you hosed your update()!) therefore you need to call database.insert(...). of course if nRowsEffected > 0 then you are done.
You can use execSQL and use INSERT OR REPLACE
String[] args = {"1", "newOrOldCategory"}; // where 1 is the category id
getWritableDatabase().execSQL("INSERT OR REPLACE INTO table_name (idColoumn, categoryColumn) VALUES (?, ?)", args);
First of all you have write function which is check whether id is exists in particular Table like:
/**
* #param table_name
* #param server_id
* #return
*/
public boolean isServerIdExist(String table_name, int server_id) {
long line = DatabaseUtils.longForQuery(mDB, "SELECT COUNT(*) FROM " + table_name + " WHERE id=?",
new String[]{Integer.toString(server_id)});
return line > 0;
}
You have to pass table_name and id in that like
/**
* INSERT in TABLE_ACCOUNT_DEVICE
**/
public long insertOrUpdateAccountDevice(int server_id, int account_id,
String device_name, String device_id,
String last_active, String itp,
String utp, int status) {
ContentValues values = new ContentValues();
values.put(ACCOUNT_DEVICE_ACCOUNT_ID, account_id);
values.put(ACCOUNT_DEVICE_DEVICE_NAME, device_name);
values.put(ACCOUNT_DEVICE_DEVICE_ID, device_id);
values.put(ACCOUNT_DEVICE_LAST_ACTIVE, last_active);
values.put(ACCOUNT_DEVICE_ITP, itp);
values.put(ACCOUNT_DEVICE_UTP, utp);
values.put(ACCOUNT_DEVICE_STATUS, status); // 0=pending, 1=active, 2=Inactive, -1=not_found
/**
* isServerIdExists
*/
if (isServerIdExists(TABLE_ACCOUNT_DEVICE, server_id)) {
values.put(ACCOUNT_DEVICE_SERVER_ID, server_id);
return mDB.insert(TABLE_ACCOUNT_DEVICE, null, values);
} else {
return mDB.update(TABLE_ACCOUNT_DEVICE, values, ACCOUNT_DEVICE_SERVER_ID + " =? ",
new String[]{Integer.toString(server_id)});
}
}
Hope it will helps you.