Recursive query with ordered values in SQLite Android - android

I have one group table with a recursive relation, so each record has a parent_id. Given a group, I need to get all the student (each belong to a group) names in all its subgroups, but ordered by student name.
Do you know if there is any "easy" way to do it? If I have to do multiple queries, then I should order the results of the different Cursors, but Cursor has no orderBy().
Any ideas? Thank you so much!

As SQLite does not support recursive queries I implemented the select with two steps:
First, I have a method called getRecursiveDiningGroupIdsAsString() that retreives all the group ids recursively whose parent id is the one you pass by parameter. The result is a String in the form of: "(2, 3, 4)" so you can later use it in an IN clause. The method looks like:
public String getRecursiveDiningGroupIdsAsString(int depth, long diningGroupId) {
Cursor childDiningGroups = mDatabase.query(
"group",
new String[] {"_id"},
"parent_id = "+diningGroupId,
null, null, null, null
);
String recursiveDiningGroupIds = "";
while (childDiningGroups.moveToNext()) {
long childDiningGroupId = childDiningGroups.getLong(childDiningGroups.getColumnIndex("_id"));
recursiveDiningGroupIds += getRecursiveDiningGroupIdsAsString(depth+1, childDiningGroupId);
}
recursiveDiningGroupIds += diningGroupId;
if (depth > 0) {
recursiveDiningGroupIds += ", ";
} else {
recursiveDiningGroupIds = "("+recursiveDiningGroupIds+")";
}
return recursiveDiningGroupIds;
}
Once I have the group ids I need, I just do a simple query using the ids returned by the previous method and that is it!
Hope it helps!

Related

Is it possible to 'randomly' select a row from a table using ormlite?

I would like to select a row from a table, but I only want to get one row and the row will be selected randomly.
I would like to select a row from a table, but I only want to get one row and the row will be selected randomly.
There isn't any special method calls which do this but there are ways that you can use the QueryBuilder to accomplish this.
If you have a numerical id, something like like should work:
qb = dao.queryBuilder();
qb.where().raw("id >= (ABS(RANDOM()) % MAX(id) + 1)");
entity = qb.queryForFirst();
Sqlite RANDOM() returns a large positive or negative integer. ABS() makes it just positive, MAX(id) allows us to then mod by the maximum id value. The +1 allows us to actually choose the max id row.
You can use queryRaw:
Relation result = null;
String query = "SELECT * from relations ORDER BY RANDOM() LIMIT 1";
try {
result = queryRaw(query, getRawRowMapper()).getFirstResult();
} catch (SQLException e) {
e.printStackTrace();
}
What I actually did was to get the List<> of the selected items from the database and then use a Random object, using the size() of the return list as the maxInt. And yes I did check for nulls.
Dao dao = getHelper().getObjectDao();
PreparedQuery<Object> query = dao.queryBuilder().[query].prepare();
Object object = null;
List<Object> resultList = dao.query(query);
if(resultList != null && resultList.size() > 0){
Random random = new Random();
int selected = random.nextInt(resultList.size() - 1);
object = resultList.get(selected);
}
It works for me:
dao.queryBuilder().orderByRaw("RANDOM()").queryForFirst();

Why my ArrayList<String> is NOT sorted correctly?

I've been searching online and trying, but I didn't find the solution.
I have the following ArrayList:
{ Cate1, Cate3, Cate6, Cate2, ...., thru Cate10 }
I gave tried the following solutions:
public ArrayList<String> GetAllCategories_ByAscOrder() {
db = getWritableDatabase();
ArrayList<String> Category_ArrayList = new ArrayList<String>();
Cursor cursor = db.query(Category_TABLE, null, null, null, null, null, Category_List + " ASC");
if(cursor != null)
{
while(cursor.moveToNext())
{
String CATEGORY = cursor.getString(cursor.getColumnIndex(Category_List));
Category_ArrayList.add(CATEGORY);
}
}
cursor.close();
return Category_ArrayList;
}
And these:
Collections.sort(CATEGORY_LIST, new Comparator<String>(){
public int compare(String obj1, String obj2)
{
return obj1.compareToIgnoreCase(obj2);
}
});
}
//OR THIS:
Collections.sort(CATEGORY_LIST, new Comparator<String>(){
public int compare(String obj1, String obj2)
{
return obj1.compareTo(obj2);
}
});
}
//OR THIS:
Collections.sort(CATEGORY_LIST, String.CASE_INSENSITIVE_ORDER);
But ALL of them gave me the same sorting results:
Cate1, Cart10, Cate2, Cate3,, etc.... Cate9
I want the sorted list to be like this:
Cate1 thru Cate10
Can someone please guide me on how I can achieve this?
Thank you very much
Edit:
I forgot to mention that I let the users freely name their Category Names.
do like this :
Collections.sort(list , new Comparator<String>(){
public int compare( String a, String b ){
// if contains number
if( a.substring(4).matches("\\d+") && b.substring(4).matches("\\d+")) {
return new Integer( a.substring(4) ) - new Integer( b.substring(4) );
}
// else, compare normally.
return a.compareTo( b );
}
});
Its sorted by lexicographical order.
If you want it sorted like that, you should switch to using two digits,
eg. Cate01, Cate02, ...
Note that this happens in Windows/Linux filesystems too (if you have numbered files in a folder).
Technically, the results you got are correct - Cart10 alphabetically comes before Cart2 (since 1 comes before 2).
Try adding leading 0s to your numbers before sorting: Cart01, Cart02, etc - though you'll need to pad with leading zeros to make sure you cover the largest you expect your list to get (if it'll be over 100 elements, you'll need more zeros).
Alternatively, why not just store it as ArrayList<Integer> and prepend with "Cart" when you go to output the results? How you ultimately solve this depends on what you want to use the values for...

How to make SQLite select query faster

Hello I am pretty new with SQLite and I am trying to deal with some database manipulation in my project.
I have a table with almost 4000 rows and this is the format of every row:
problem_id (string)
problem_no (string)
problem_title (string)
dacu (int)
I need to query a bunch of problem_no based on the problem_id. The quantity of query is almost 1000 at a time. So I wrote a query code like this:
Set<Integer> getProblemsTitle(HashSet<String> problemsIDs) {
SQLiteDatabase db = this.getReadableDatabase();
HashSet<Integer> problemNo = new HashSet<Integer>();
Cursor cursor = null;
for (Iterator<String> iterator = problemsIDs.iterator(); iterator.hasNext();) {
cursor = db.query(CommonUtils.PROBLEM_TABLE, new String[] {
CommonUtils.KEY_PROBLEM_NO },
CommonUtils.KEY_PROBLEM_ID + "=?",
new String[] { iterator.next() }, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
problemNo.add(cursor.getInt(0));
}
cursor.close();
}
db.close();
Set<Integer> set = new TreeSet<Integer>(problemNo);
return set;
}
I know this is not a optimized snippet. And I need to optimize it a lot to reduce the execution time of the query. I did it inside AsyncTask but it is taking too much time.
How can I do this efficiently with faster performance?
You might want to consider taking this out of the database. If you just grabbed all the problems, you could add them all in code. Running one SELECT with 4000 results is still going to be much faster than a thousand SELECT statements.
The approach would be to grab them all, but sorted(ORDER BY problem_id). You could then just check each item in problemIDs against it, and add when you get a match.
You could also use the IN operator as Mathew suggests, but I don't know how efficient that will be with 1000 items in the set.
Don't iterate over a collection of IDs, but use the IN operator in a WHERE condition.
SELECT * FROM Table WHERE problem_id IN (1,2,3,4,5)
This will return all the records in the set. Whereas you are querying them one at a time.
You could try compiling a query, and maybe you can try to load the database into memory before reading.
Create an index on the problem_id column.

android sqlite database cursor

I have an android application which has a small database as a db file in the asset folder. The file is called nametoareamap.db.It has a single table named 'map'. The table has two columns(Names and Areas) as following:
Names Areas
Aaron A
Chris A
Helen B
Tim B
My application takes names as input from the user. Suppose some user had input: Aaron, Tim.
In this case, in terms of name there are two matches with the database. But they come from different areas. Aaron from A and Tim from B. I want to implement the following logic.
If match > = 2 && the area of the matches are same
{ i take a decision}
else
{i decide something else }
Can anyone kindly provide me the code required to do this with cursor and sqlite databases on Android. I have a database adapter already.Thanks in advance
Assuming the following table layout
CREATE TABLE name_area (
_id INTEGER PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
area TEXT NOT NULL,
UNIQUE(name, area)
)
And the following values
name area
---- ----
Aaron A
Chris A
Bunny A
Ron A
Burgundy B
Helen B
Tim B
Say you want to know if Aaron, Ron and Burgundy all are in the same area or not:
SELECT COUNT(*), area FROM name_area
WHERE name='Aaron' OR name='Ron' OR name='Burgundy' GROUP BY area
This would return two rows.
2 A
1 B
i.e. two of the are in the same area (A), one is in another (B):
Expressed as a Cursor you could check it like this:
Cursor cursor = ...; // Format your query & do the SELECT
try {
if (cursor.moveToNext()) {
int count = cursor.getCount();
if (count < 2) {
// Everyone is in the same area
int n = cursor.getInt(0);
// Now verify 'n' against the number of people you queried for
// if it doesn't match one or more didn't exist in your table.
} else {
// People are in different areas
int n = 0;
do {
n += cursor.getInt(0);
} while (cursor.moveToNext());
// Now verify 'n' against the number of people you queried for
// if it doesn't match one or more didn't exist in your table.
}
} else {
// Oops nothing was found.
}
} finally {
cursor.close();
}

What to do with Cursor after a SQLite query?

This is my first time using a database and I'm not really sure how this works. I made the database and made a query that returns a cursor and... now what? What is a cursor, really? Can I just use that to navigate through my data or do I have to put it in an ArrayList or ListActivity or what?
You need to iterate the cursor to get your results.
Use cursor.moveToFirst() and/or cursor.moveToNext() (with a while loop). Then you can use the getX() method, like cursor.getInt() or cursor.getString().
For example, ir your are expecting one result from your query:
if (cursor.moveToFirst()) {
String name = cursor.getString(cursor.getColumnIndex('NAME'));
int age = cursor.getInt(cursor.getColumnIndex('AGE'));
} else {
// oops nothing found!
}
First call cursor.moveToFirst(). Each time you call cursor.moveToNext() it will move to the next row. Make sure when you are done with your cursor you call cursor.deactivate() or you will get errors in your log cat.
Iterate over the returned Cursor instance
public List<Object[]> cursorToTableRows(Cursor cursor) {
List<Object[]> result = new ArrayList<Object[]>(cursor.getCount());
cursor.move(0);
cursor.moveToNext();
while (cursor.isAfterLast() == false) {
Object[] tableRow = new Object[cursor.getColumnCount()];
for(int i=0; i<cursor.getColumnNames().length; i++) {
int columnIndex = cursor.getColumnIndex(cursor.getColumnName(i));
String columnValue = cursor.getString(columnIndex);
tableRow[i] = columnValue;
}
result.add(tableRow);
cursor.moveToNext();
}
cursor.close();
return result;
}
Then create the desired objects.
public List<Vehicle> getVehicles() {
List<Vehicle> vehicles = new ArrayList<Vehicle>();
Cursor cursor = null;
List<Object[]> objects = cursorToTableRows(cursor);
for(Object[] row : objects) {
int i=0;
Vehicle vehicle = new Vehicle(row[i++].toString(), row[i++].toString()));
vehicles.add(vehicle)
}
return vehicles;
}
from Developer.android: This interface provides random read-write access to the result set returned by a database query.
In other words: query returns you a set of data represented by a cursor. First you need to make sure you got a valid cursor (not null) and then try to move it to desired position in the data set (use moveToXXX methods). In order to obtain data pointed by cursor use getXXX methods. When done using it make sure to call close to release resources.
According to this link it looks like you can iterate through the query return using something like:
cursor.next();
And grab the data at the location you are looking for using:
cursor.getString(0)
After you successfully have your Cursor setup, you would typically want to display that to a view in some form.
Have a look at the following answer for a detailed, but simple example of using a Cursor Adapter to pair up your newly-minted Cursor with your desired XML View:
https://stackoverflow.com/a/20532937/293280

Categories

Resources