I'm developing my firs app for android right now, I am using multiple tables to get and insert data. during the development and found myself fetching data from the table with has only two columns STATS(_id, stat_name). What my problem is? I have an activity with 10 buttons, and every button correlates with one stat_name. When users presses one of the buttons application is "going" to STATS table to get correct _id and then is inputting this _id to another table GAME_STATS(_id, PlayerId (fk), GameId(fk), StatsId(fk)(andmore)) on STATS._id = GAME_STATS.StatsId and I basicly have to do similar operation for PlayerId.
Right now, I'm doing it this way:
public String getStatId(String statName){
String statId = "Error";
Cursor c = mDb.query(STAT_TABLE, new String[] {AbstractDbAdapter.STAT_ID, AbstractDbAdapter.STAT_NAME}, AbstractDbAdapter.STAT_NAME+ " = " +statName, null, null, null, null);
int count = c.getCount();
if(count == 1){
c.moveToFirst();
statId = c.getString(c.getColumnIndex(AbstractDbAdapter.STAT_ID));
}
c.close();
mDb.close();
Log.d("FootballApp","StatId =" +statId);
return statId;
}
What my problem is, that I know that there SHOULD be only one value returned, and I still have to use Cursor, to do so. Also, in my opinion, it looks way to complicated and time consuming wo write all that code just to get one id from one table. I have 9 tables in my application, and I will have to write similar method every time I need _id from different table when I have, for example, only name.
Can someone tell me if there is easier way to do all that? Please :)
thanks! :)
I think it doesn't get much simpler than that. However you can make the method more generic so you can reuse the code:
public String getFromDb(String tableName, String select, String selectBy, String selectName){
String selection = "Error";
Cursor c = mDb.query(tableName, new String[] {select}, selectBy + "=" + selectName, null, null, null, null);
if(c.getCount() == 1){
c.moveToFirst();
selection = c.getString(c.getColumnIndex(select));
}
c.close();
mDb.close();
Log.d("FootballApp", select + "=" + selection);
return id;
}
Example usage:
int statID = getFromDb(STAT_TABLE, AbstractDbAdapter.STAT_ID, AbstractDbAdapter.STAT_NAME, statName);
That is about as simple as it gets, but Cursor.moveToFirst() returns false if the cursor is empty so you can cut out the c.getCount() call and just say if(c.moveToFirst()) instead. That will save you a little bit of typing :)
Related
So I've been trying to convert content of a SQLite Database to Objects in an ArrayList. To do that, I've tried to iterate through the Table like written in the code below. But this doesn't return each mark of the specified subject once, but iterates through the table about 70-80 times. I think I know the problem, being that the c.moveToNext moves to the next column of the row and not the next row, but I don't know the solution to this.
public ArrayList<Marks> toMarksList(String subject){
ArrayList<Marks> marksArrayList = new ArrayList<Marks>();
SQLiteDatabase db = getWritableDatabase();
String query = "SELECT * FROM " + TABLE_MARKS + " WHERE " + COLUMN_SUBJECT + "=\"" + subject + "\";";
Cursor c = db.rawQuery(query, null);
c.moveToFirst();
while(!c.isAfterLast()){
if(c.getColumnIndex("subject")!=0){
String dbName = c.getString(c.getColumnIndex("name"));
Double dbValue = c.getDouble(c.getColumnIndex("value"));
Double dbWeight = c.getDouble(c.getColumnIndex("weight"));
marksArrayList.add(new Marks(subject, dbName, dbValue, dbWeight));
}
c.moveToNext();
}
db.close();
return marksArrayList;
}
This code seems to be seriously broken, because it also gets the wrong name for the third entry in the database, but onnly in the first half of the while loops. How do I make it so the cursor is at one row, reads the needed entries of that row and then continues to the next row?
EDIT: Turns out I'm completely stupid and kept adding new entries to the list every time I launched the app.
But this doesn't return each mark of the specified subject once, but iterates through the table about 70-80 times.
I don't see evidence of iterating over the table multiple times.
If that's what you're observing somehow,
it's not in the posted code, but somewhere in the caller of this method.
In any case, I suggest improving the main loop in there, like this:
Cursor c = db.rawQuery(query, null);
while (c.moveToNext()) {
String dbName = c.getString(c.getColumnIndex("name"));
Double dbValue = c.getDouble(c.getColumnIndex("value"));
Double dbWeight = c.getDouble(c.getColumnIndex("weight"));
marksArrayList.add(new Marks(subject, dbName, dbValue, dbWeight));
}
db.close();
See the edit, I just kept adding Data to the Database, which I noticed when the length of the ArrayList kept going up.
Let me just dig a hole and disappear in it.
I've created an object that I need to save so the user can access the information in it later. I was using other questions, and tutorials to put it into a JSONobject, and then turn that into a string. After that, I would insert it into a table...
JSONObject json = new JSONObject();
json.put("run", run);
String runString = json.toString();
SQLiteDatabase database = openOrCreateDatabase("your runs",MODE_PRIVATE,null);
database.execSQL("CREATE TABLE IF NOT EXISTS Runs(Run BLOB);");
database.execSQL("INSERT INTO Runs VALUES('"+runString+"');");
To retrieve it I use this code...
cursor = database.rawQuery("Select * from Runs",null);
cursor.moveToFirst();
runArray = new Run[cursor.getCount()];
while(cursor.moveToNext()){
try {
object = new JSONObject(String.valueOf(cursor.getBlob(0)));
run = (Run) object.opt("run");
runArray[count] = run;
count ++;
} catch (JSONException e) {
e.printStackTrace();
}
}
This seems to work, but when I try to get a Run from the runArray, and get the name of the run it causes a null pointer exception. The runArray has a length of one, which should be correct because I only created one Run. Is this the proper way to retrieve the Runs, or should I be going about this a different way?
I figured it out. Instead of trying to put the Run object into the table. I just put all of the values from Run into the table. In the other activity that retrieved the values, I took the values and created a new Run with them.
Here's the code that inserts the values...
SQLiteDatabase database = openOrCreateDatabase("your runs",MODE_PRIVATE,null);
database.execSQL("CREATE TABLE IF NOT EXISTS Runs(name VARCHAR, units VARCHAR, runtime VARCHAR, date VARCHAR, pace FLOAT, avgSpeed FLOAT, distance FLOAT, laps BLOB, speeds BLOB, distances BLOB);");
database.execSQL("INSERT INTO Runs VALUES('"+run.getName()+"','"+run.getUnits()+"','"+run.getRunTime()+"','"+run.getDate()+"','"+run.getPace()+"','"+run.getAvgSpeed()+"','"+run.getDistance()+"','"+Arrays.toString(run.getLaps())+"','"+Arrays.toString(run.getSpeeds())+"','"+Arrays.toString(run.getDistances())+"');");
And here's the code that retrieves it...
database = openOrCreateDatabase("your runs",MODE_PRIVATE,null);
cursor = database.rawQuery("Select * from Runs",null);
cursor.moveToFirst();
runArray = new Run[cursor.getCount()];
count = 0;
while(!cursor.isAfterLast()){
run = new Run();
run.setName(cursor.getString(0));
run.setUnits(cursor.getString(1));
run.setRunTime(cursor.getString(2));
run.setDate(cursor.getString(3));
run.setPace(cursor.getFloat(4));
run.setAvgSpeed(cursor.getFloat(5));
run.setDistance(cursor.getFloat(6));
run.setLaps(toArray(new String(cursor.getBlob(7))));
run.setSpeeds(toFloatArray(new String(cursor.getBlob(8))));
run.setDistances(toFloatArray(new String(cursor.getBlob(9))));
runArray[count] = run;
count++;
cursor.moveToNext();
}
I'm not sure if this is the best way, but it works for now. I can improve it later.
This might be stupid question but this code is not working..
String sql= "SELECT field, question, choice1, choice2, choice3, choice4, answer "
+ "FROM WineQuiz ORDER BY RANDOM() LIMIT 5";
Intent i = getIntent();
String mField1 = i.getStringExtra("FIELD1");
String mField2 = i.getStringExtra("FIELD2");
String mField3 = i.getStringExtra("FIELD3");
if(mField1!="" || mField2!="" || mField3!=""){
sql = "SELECT field, question, choice1, choice2, choice3, choice4, answer "
+ "FROM WineQuiz WHERE field='"+mField1+"' or field='"+mField2+"' or field='"+mField3+"' ORDER BY RANDOM() LIMIT 5";
Cursor c =db.rawQuery(sql, null);
What I'm trying to do is simple. I'm creating quiz app, which has SelectActivity sending string data of quiz field into this class receiving it with variables of mField1,2,3.
If SelectActivity does not send any string, the first sql(variable) is put into the query.
If one of the field is chosen, mField1 or 2 or 3 receives string data, then the second sql is put into the query.
However, the first sql querying does not work while the second one works well.
When I use the first sql query independently, it works pretty well. Thus, the first and second sql seems unable to exist at the same time though those two query has no problem by themselves.
Why is that??
Replying the comments, "Not work" means cursor has no data. My continuing code is below, and the error log "Cursor has no data" shows up. It literally means those array does not store any data.
Cursor c =db.rawQuery(sql, null);
if (c.getCount() > 0) { // If cursor has at least one row
c.moveToFirst();
do { // always prefer do while loop while you deal with database
cPos = c.getPosition();
array[cPos][0] = c.getString(c.getColumnIndex("field"));
array[cPos][1] = c.getString(c.getColumnIndex("question"));
array[cPos][2] = c.getString(c.getColumnIndex("choice1"));
array[cPos][3] = c.getString(c.getColumnIndex("choice2"));
array[cPos][4] = c.getString(c.getColumnIndex("choice3"));
array[cPos][5] = c.getString(c.getColumnIndex("choice4"));
array[cPos][6] = c.getString(c.getColumnIndex("answer"));
c.moveToNext();
//Retrieves whether the cursor is after the last row in this SQLServerResultSet object.
} while (!c.isAfterLast());
} else {
Log.e("SQL Query Error", "Cursor has no data");
}
I'm storing a number of objects for my app in an SQLite Database. The class for these objects has a constructor that takes a Cursor object, passed in from the Database class. Example:
public MyClass(Cursor cursor) {
this.id = cursor.getString(cursor.getColumnIndex(MyDatabase.KEY_ROWID));
this.nickname = cursor.getString(cursor.getColumnIndex(MyDatabase.KEY_NICKNAME));
...and so on.
However I've noticed that at random times I've been getting a crash when getColumnIndex for the ID column returns -16. (And if I comment out that line, whichever the first column I try to access is, it will also return -16). I've added some extra logging around it but it hasn't helped as it seems like the columns are fine:
public MyClass(Cursor cursor) {
Log.i("TEST", Column names are: " + Arrays.toString(cursor.getColumnNames()));
Log.i("TEST", Making object, id column index is " + cursor.getColumnIndex(MyDatabase.KEY_ROWID));
Which prints:
Column names are: [_id, nickname...]
Making object, id column index is -16
So it sees like everything should be fine, anyone got any clue why everything could be getting so messed up while reading from the Cursor?
EDIT: Here's how I'm getting the cursor, this is a method in the database class:
public MyObject getMyObject(String id) {
MyObject objectFound = null;
String[] whereArgs = { id };
Cursor cursor = db.query(true, getTableName(), null, WHERE_EQUALS, whereArgs, null, null, null, null);
if(cursor.moveToFirst()) {
//Should only return 1 entry from DB
while(cursor.isAfterLast() == false) {
objectFound = new MyObject(cursor);
cursor.moveToNext();
}
}
cursor.close();
return objectFound;
}
How to get Group ID knowing contact's Number
I guess it have to be another query inside this one, but I have not ANY idea how to do it
Here what I've tried:
String[] projection = new String[]{ ContactsContract.Groups._ID };
Cursor cursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection,
ContactsContract.CommonDataKinds.Phone.NUMBER +" = "+ number,
null,
null);
cursor.moveToNext();
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Groups._ID));
(Query returns nothing)
Thanks for help!
Your query returns nothing, because there is no such column Groups._ID within dataset CommonDataKinds.Phone.
Try something like this:
String sPhoneNumber = "+48123456789";
Cursor cursor = getApplicationContext().getContentResolver().query(
Data.CONTENT_URI, new String[] {CommonDataKinds.GroupMembership._ID},
ContactsContract.CommonDataKinds.Phone.NUMBER+"='"+sPhoneNumber+"'", null, null);
where sPhoneNumber is String with desired phone number. Keep in mind, that your cursor may still return 0 depending on:
how your phone number is formatted, i.e. you wish to find group ID
for contact of given number +49123456789 while number is formatted
like this +49 123 456 789. Whitespaces are making this completely
different String.
your contact does not belong to any group.
Also cursor can still return more results, mostly in cases when your contact belongs to more than one group.