Get random record in SQLite - android

I fetch records in my SQLite database like this.
spellId = extra.getString("spellId");
DBase db = new DBase(this);
db.open();
String[] data = db.getRecord(Integer.parseInt(spellId));
db.close();
Can I get random data like this without using raw queries and cursor?

try like this:
db.rawQuery("SELECT * FROM mainTable ORDER BY RANDOM() LIMIT 1", null);

You can use Random#nextInt() like
String[] data = db.getRecord(new Random().nextInt(num));
where num falls in the range of your record IDs. You would need to adapt this solution in case your Ids are fragmented and do not form a consecutive range.
One of the ways to do that would be to first create a query to fetch all the primary keys and store the values in a set somewhere. Then pick a random key by generating an index using Random.
String[] data = db.getRecord(IDSet.get(new Random().nextInt(IDSet.size())));
Check out the docs for more information.
Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive), drawn from this random number generator's sequence.
If you're considering a DB query solution
A better alternative to using ORDER BY RANDOM() (which is known to not scale well as the number of rows in your table grows) is to let SQLite return a random row using an OFFSET.
First save the total number of rows num somewhere.
SELECT COUNT(*) AS num FROM spells;
Then choose a random number rnum between (0, num) using Random and use the query
SELECT * FROM spells LIMIT 1 OFFSET rnum;

Related

Random data display to TextView in android

Any help me? I want to display random data from SQliteDB to multi TextView, thanks!
protected void setQuestionView(){
txta.setText(currentQ.getOptOne());
txtb.setText(currentQ.getOptTwo());
txtc.setText(currentQ.getOptThree());
txtd.setText(currentQ.getOptFour());
Assuming that you've extracted the data as a cursor, you could get the number of rows using int randomrange = (cursor.getCount()) -1; (obviously if range is less than 0 then there are no rows).
Once you have obtained the random number as an integer, then you can use cursor.moveToPosition(randomposition) to move the cursor. You can then do txta.setText(cursor.getString(columnoffset)); or if you wish to use the column's name then you could use txta.settext(cursor.getString(cursor.getColumnIndex(columnasstring)));
You could then repeat this 4 times. However, you have a chance to have the same text values.
An alternative way is to have the cursor extract the required number of random rows e.g. base the query on the following SQL :-
SELECT * FROM yourtable ORDER BY RANDOM() LIMIT 4;

Sugar orm, how to delete duplicate records?

I'm using sugar orm for a high scores database, and after a lot of searching(because the documentation is very pure and also some links are dead), I've managed to save and list the records from the database. Unfortunately I cannot find out how to delete the duplicated score records, or how to update a record instead of saving a new one in case the name and high score values are the same.
I found that this can be done with something like this:
getWritableDatabase().execSQL("delete from highscores where _id not in (SELECT MIN(_id ) FROM highscores GROUP BY highscores_id)");
}
but how can I do it with sugar orm in which I don't know if it even has a id field or its name ?
UPDATE:
Following #Juancortes' s advice I'm trying to check for the current player, if the current score exists in database, before add the record:
private void saveScore(){
int total;
total=checkList();
if(total>0) {
HighScoresDB highScores = new HighScoresDB(tvPlName.getText().toString(), total);
highScores.save();
}
}
private int checkList(){
String tempName=tvPlName.getText().toString();
List<HighScoresDB> check = HighScoresDB.find(HighScoresDB.class, "person = ?",tempName);
ArrayList<Integer> templist = new ArrayList<Integer>();
for(int i=0;i<check.size();i++){
templist.add(check.get(i).score);
}
int total = Integer.valueOf(totalPts.getText().toString());
if(templist.contains(total)) {
total = 0;
}else{
total=Integer.valueOf(totalPts.getText().toString());
}
return total;
}
I get a list with the existing records for current player using sugar orm. After I'm checking if the list contain the current score value, and if is true I set it to "0". Then in "saveScore()" method I save a record only if the score value is greater that "0". But this doesn't work and I keep getting double, triple etc records. What I'm doing wrong?
UPDATE 2:
Seems that "contains" doesn't work for the list with the database objects directly. So I created an ArrayList with only the scores(code updated too), and I used that list to check if the total exists. Now seems that works fine and don't created double records.
A little late, but you can use the executeQuery() method for a raw custom query. Here is an example of a query that will remove duplicates:
DELETE tableName FROM tableName LEFT OUTER JOIN(
SELECT MIN(table_primary_key) AS rowId, col1, col2, col3
FROM tableName
GROUP BY col1, col2, col3
) as KeepRows ON tableName.table_primary_key = KeepRows.rowId
WHERE KeepRows.rowId IS NULL
Compares all the rows, finds any duplicates, deletes them.
This will execute in SQL without having to pull back all the records, though you can modify it to a SELECT and then use the SugarORM delete functionality. That will increase memory usage though.

How to select data from a table and save it in a variable in android

I have a MySQL table with the rows amount and aid. I need the sum of amounts which have a certain aid. The aid, I will be declaring in the android class. For example, I want to select the sum of amounts for aid 12. How can I do this? The problem is if I run an SQL command in the android class like this,
SQLiteDatabase dbq = openOrCreateDatabase("shareity", Context.MODE_PRIVATE, null);
dbq.execSQL("SELECT amount FROM donations WHERE activityid = aid");
i don't think this will succeed, coz the aid I need is declared in the android class itself. Any help please?
This is wrong
dbq.execSQL("SELECT amount FROM donations WHERE activityid = aid");
You need to do this.
Cursor c = dbq.rawQuery("SELECT amount FROM donations WHERE activityid = 'aid'", null);
Edit : If aid is variable means you need to modify like this
Cursor c = dbq.rawQuery("SELECT amount FROM donations WHERE activityid = '"+aid+"'", null);
Read value from this cursor.
Update 2
Here you want the sum of amount column so change your query as follows.
Cursor c = dbq.rawQuery("SELECT sum(amount) FROM donations WHERE activityid = '"+aid+"'", null);
Here the condition is amount column is might Integer in your Create Table query.
To select data from table, you have to execute the select query and it would return data in cursor. After that you have to iterate through the cursor to get the data.
P.S. I am giving you a ready code because there are plenty of resources available on the net, try to search and post comment if you will face any issue!

Using Max in ORMLITE?

I need to use max in ORMLITE to retrieve the latest record in ormlite table
Similar to select max(MODIFIED)FROM TABLE;
I want to get a single record that has maximum value for datemodified having where userid is id; for particular userid i want to find record with maximum value for date ie to find the latest entry of particular user
Can't quite tell but I assume you want to know how to query for some object whose MODIFIED field is equal to the max value using ORMLite. I'm not sure you can do this in SQL without two queries. I think you are going to have to do a raw query to get the max and then do another query.
I added queryRawValue(...) to ORMLite in version 4.42 so you can do:
long max = fooDao.queryRawValue(
"select max(modified) from foo where userid = ?", id);
// now perform a second query to get the max row
Foo foo = fooDao.queryBuilder().where().eq("modified", max).queryForFirst();
By hand you would do:
GenericRawResults<String[]> rawResults =
fooDao.queryRaw("select max(modified) from foo where userid = ?", id);
// there should be one result
long max = Long.parseLong(rawResults.getResults().get(0)[0]);
// now perform a second query to get the max row
Foo foo = fooDao.queryBuilder().where().eq("modified", max).queryForFirst();

Android how to query huge database in android (cursor size is limited to 1MB)

I'm working to develop an application that has to query at some time, a database with over 4k rows, and each row has 90 fields (Strings). The problem is that if I select * from database, my cursor gets really big (over 4MB). And the cursor in android is limited to 1MB.
How can I solve this, or what's the most elegant method to workaround this?
It is possible to split database in smaller chunks and query them out?
I found a way to handle this and I want to share with all who need it.
int limit = 0;
while (limit + 100 < numberOfRows) {
//Compose the statement
String statement = "SELECT * FROM Table ORDER someField LIMIT '"+ limit+"', 100";
//Execute the query
Cursor cursor = myDataBase.rawQuery(statement, null);
while (cursor.moveToNext()) {
Product product = new Product();
product.setAllValuesFromCursor(cursor);
productsArrayList.add(product);
}
cursor.close();
limit += 100;
}
//Compose the statement
String statement = "SELECT * FROM Table ORDER someField LIMIT '"+ (numberOfRows - limit)+"', 100";
//Execute the query
Cursor cursor = myDataBase.rawQuery(statement, null);
while (cursor.moveToNext()) {
Product product = new Product();
product.setAllValuesFromCursor(cursor);
productsArrayList.add(product);
}
cursor.close();
The main idea is to split your data, so you can use the cursor as it should be used. It's working under 2 s for 5k rows if you have indexed table.
Thanks,
Arkde
Well as a rule you never do select *. For a start each row will have a unique identifier, and your user will want to select only certain rows and columns - ie what they can see on an android screen. Without appearing to be rude this is a pretty basic question. You only return the columns and rows you want to display for that screen on the phone - otherwise you consume unnecssary battery life transfering never to be diaplayed data. the standard approach is to used parameterised stored procedures. Google parameterised stored procedures and do a little reading - by the by - you cant update any table unlees you return the unique row identifier for that table.
Do you need all these rows at the same time? Can you fetch them in parts? This question has been asked several times: Android SQLite and huge data sets
Here's one more suggestion: If you have 90 fields that you need to modify, split them into 10 different views. On each view have a left arrow and right arrow so you can horizontally traverse across screens. Hence each view will show 9 fields. Or some strategy like that. Essentially these are all the same views except for column names so you shouldn't have to modify much code.

Categories

Resources