I have a listview that show some items, each item contains attribute called category Id, this is attribute is related to one of my database taples
I need for each item to open database, make a query to get category object where id = item category id and then show data in the listview
it is very heavy to open database to read record by record
can anyone advice how to solve this problem without opening database many times?
Thanks
you can red the data base once. Get all data at the same time. then read the desired data from the returned array.
//returns data from DB
String[] array = getInfoDataBase();
//array example
array = ["id1", "name1", "data2","id2", "name2", "data2", ....]
for (int i = 0; i < array.length; i = i+3) {
if (array[i] == //desired id) {
//get your data from the array like name1, data1
break; // to stop the fro loop
}
}
You can use JOINS for this purpose.
SELECT * FROM item INNER JOIN category ON item.categoryId = category.id WHERE item.id in (id1, id2, id3)
You will have to replace (id1, id2, id3) with the item Ids in your table.
Related
I would like to delete mutiple items from SQLite in batch basing on their ID column.
What I have is a HashMap which contains objects which one of field is pID (unique ID in DB).
So, here's my code:
/*
Delete rows from DB
*/
val selection = "${BaseColumns._ID} = ?"
// Create a list of product ID's to delete
val dbDeletor = dbHelper.writableDatabase
// Temp array to store ID's in String format
val tempIDs = ArrayList<String>()
// Loop through array of items to be deleted
for(i in ProductsRecyclerAdapter.productsToDeleteArray)
tempIDs.add(i.value.pID.toString())
// Perform deletion in DB
val deletedRowsCount = dbDeletor.delete(ProductsEntry.TABLE_NAME, selection, tempIDs.toTypedArray())
// Show snackbar with count of deleted items
Snackbar.make(mainCoordinatorLayout, "Products deleted: $deletedRowsCount", Snackbar.LENGTH_SHORT).show()
Everything works great when I'm deleting only 1 item but if tempIDs array contains 2 or more I'm receiving following Exception:
Too many bind arguments. 3 arguments were provided but the statement needs 1 arguments.
Maybe the reason is that I'm converting pID of type Long into String in order to delete rows in batch? I did not find any other solution. Please take a look and comment.
Your query looks somewhat like that:
DELETE FROM ProductsEntry.TABLE_NAME WHERE BaseColumns._ID = ?
There is only 1 argument ? but you're passing 3 values (IDs). You want to use IN statement instead, and print your params separated by comma:
// IN instead of equal to compare multiple values
val selection = "${BaseColumns._ID} IN (?)"
// your code to obtain IDs here
// .....
// combine all values into single string, ie. 1, 2, 3, 4 and wrap it as an array
val selectionArg = arrayOf(tempIDs.joinToString())
// Perform deletion in DB
val deletedRowsCount = dbDeletor.delete(ProductsEntry.TABLE_NAME, selection, selectionArg)
I have a listview with some name and url.. After my app starts I check if there is any record in my local database First clear my old records then fill table columns with listview data and if there isn't just insert data... this is how I'm doing it :
List<LocalProduct> allAuthors = LocalProduct.listAll(LocalProduct.class);
if (allAuthors == null) {
for (int allList=0;allList<adapter.getCount();allList++){
Product my = adapter.getItem(allList);
String offline_name = my.name.toString().trim();
String offline_url = my.image_url.toString().trim();
LocalProduct book = new LocalProduct(offline_name, offline_url);
book.save();
}
}else {
allAuthors.clear(); //I tried this
allAuthors.removeAll(allAuthors); //And this
for (int allList=0;allList<adapter.getCount();allList++){
Product my = adapter.getItem(allList);
String offline_name = my.name.toString().trim();
String offline_url = my.image_url.toString().trim();
LocalProduct book = new LocalProduct(offline_name, offline_url);
book.save();
}
}
But my table records are still storing same records after every start ..
What is the correct way !?
Insert this line before intialize LocalProduct class list:
SugarRecord.deleteAll(LocalProduct.class);
Example:
SugarRecord.deleteAll(LocalProduct.class);
List<LocalProduct> allAuthors = LocalProduct.listAll(LocalProduct.class);
clear() and removeAll() only remove item from List (which is in memory when loaded) not remove record in database.
If you want to clear record in database you need to use :
db.delete(TABLE_NAME, null, null);
I have a listview in which i am adding the items whose values are retrieved from the table in my database. Now, in the current scenario, if i am deleting an item, i am passing the complete string and breaking it in parts to provide information to my delete query.
Instead of all these dumb work, i can simply pass the id of that particular item, but the id is not in the string array which is binded to the listview. How can i delete items from the database by simply using the item's id...?
Note: id is the column in table, so i have each item's id from database. But i am not displaying it in the listview.
String[] records = new String[report.size()];
for(int i = 0; i<report.size(); i++)
{
if(report.get(i).getDate()!="")
{
String eachRecord = (i+1) +". "+report.get(i).getDate() + " -- " + report.get(i).getType();
records[i] = eachRecord;
}
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.singlerow, records);
listView.setAdapter(adapter);
You should map the data you are getting from the Database to a java object.
Read the data from the db store in list or array whatever you like.
Create your custom adapter by extending the BaseAdaper REF and pass your list of object to it.
In Adapter's getView build your view.
Now when you delete your list item you can easily find that object and ask for the id of it. You can use this id to delete the item from db. Now you can refresh the list with the remaining data.
Am doing one small android app. In that i have Expandable listview and am trying to populate data's from SQLite. So that i used HashMap to store parent(String) and child(ArrayList).
For eg I have four integer no's in parent(1, 2, 3, 4) i get this and stored in ListArray. Now i need to get child(ListArray) for that particular parent. Parent 1 contain (aa, bb), parent 2 contain (cc).. etc, now see this code
try
{
header = new ArrayList<String>();
footer = new ArrayList<String>();
child= new HashMap<String, List<String>>();
String date = null;
int count=0, countchild=0;
Cursor c = db.rawQuery("SELECT Date FROM Table", null);
if (c.moveToFirst())
{
do
{
date=c.getString(c.getColumnIndex("Date"));
header.add(date);
count=count+1;
} while (c.moveToNext());
}
for (int i = 0; i < count; i++)
{
String temp=header.get(i);
Cursor cc=db.rawQuery("SELECT Id FROM Table WHERE Date ='"+ temp +"' ", null);
if(cc.moveToFirst())
{
do
{
countchild=countchild+1;
String id=cc.getString(cc.getColumnIndex("Id"));
//footer.clear(); // it clear all data's on child
footer.add(id);
Log.d("Footer date count", "" + countchild);
child.put(temp, footer);
}
while (cc.moveToNext());
//footer.clear(); // it clear all data's on child
}
footer.clear(); // it clear all data's on child
}
}
I want to clear footer here after adding it to child then only i will get proper Expandable listview. If i remove/comment this footer.clear() line then all child's are added to all parents. eg parent 1 contain (aa, bb, cc, etc) and parent 2 contain (aa, bb, cc, etc). If i leave this footer.clear() line then all child's are cleared and display only parent like this eg Parent 1(), Parent 2()... etc
How to clear this footer(ListArray) after adding it to HashMap ?? or tell me some suggestion to modify this code.
Thank you. Srihari
When you put the ArrayList to the HashMap, the HashMap actually saves a reference to your array, not a copy.
That's why you must use different arrays for each group:
for (int i = 0; i < count; i++)
{
List<String> children = new ArrayList<String>();
String temp = header.get(i);
Cursor cc = db.rawQuery("SELECT Id FROM Table WHERE Date ='"+ temp +"' ", null);
if(cc.moveToFirst())
{
countChild += cc.getCount();
Log.d("Footer date count", "" + countchild);
do
{
String id = cc.getString(cc.getColumnIndex("Id"));
children.add(id);
child.put(temp, children);
}
while (cc.moveToNext());
}
}
As you can see a new children ArrayList here is created for each group and it's never cleared as that would clear the values from HashMap also.
Furthermore I've let myself fix a few other things like using Cursor's getCount method, to get the count instead of looping. Also I'm not using the footer array as it's unnecessary in the code you've shown.
Lastly, please use understandable and meaningful names for your variables as it can help you as well as others who read your code.
Remember Java is OO so if you clear an instance of an object, in this case an ArrayList, every other object referencing to it will get that new value.
What I recommend is you create a new instance of your footer variable everytime you need to fill a new group of your expandable list view, that way every footer list instance you create will be "associated" with one group in your list.
Hope this helps. :)
I am having some trouble implementing a sqlite database in my simple android application:
a user is displayed a list of animals in a Listview.Upon selecting an animal the user is brought to an activity "Animal",which will display a picture of the animal and give them options to
view Animal Bio
Back
All very simple so far, right?
I have working the database, which will populate the listView of animals.Database currently looks like
Table Animal-
_ID,
Name
Table Biography-
_ID,
Bio
This is where I would welcome any helpful advice on my problem, or on how to improve my implementation.
Currently populating the DB as follows
long populateDB(){
String[] animalName = {"Lion" "Zebra", "Tiger", "Gorilla",...};
String[] animalBios = {"Found in the "...}
ContentValues animalNameVals = new ContentValues();
ContentValues animalBioVals = new ContentValues();
long[] rowIds = new long[animalName.length];
// Populate the animal table
for(int i = 0; i < animalName.length; i++){
animalNameVals.put(KEY_ANIMALNAME, animalName[i]);
rowIds[i] = db.insert(ANIMAL_TABLE, null, animalNameVals);
}
// Populate the Bio table
for(int j = 0; j < bios.length; j++){
animalBioVals.put(KEY_BIO, bios[j]);
rowIds[j] = db.insert(BIOS_TABLE, null, animalBioVals);
}
return rowIds[0];
}
And had planned on being able to tell database which animal on list was selected by passing extras with the intent, eg if position on listItemClick == 1, pass in tiger and retrieve tiger bio from db.
Problems:
Then on the Animal activity page is getExtra() == tiger, telling the activity that tiger was selected from the list and to load this bio from the DB..well, I cannot see an efficient method of implementation for this idea and am struggling to do so.
My second headache comes from adding the bio to the application from the Db.Originally I had a test bio hardcoded in a string, shown in a TextView.Is there a way to retrieve a string from a cursor and add it to the TextView id?I understand I will need some adapter, what I do not understand is why cant it be as simple as setResource(R.id.bio) = bio.
Thanks you for reading and any help is much appriciated.
First problem: First of all, I'm not sure why you don't have the column Bio in the Animal-table? As no Bio would fit to any other animal than itself, you can safely do this. By doing this you can query the database upon selection and pass the entire object (including name of animal and bio) to the next Activity and use this to get your information. If this was somewhat unclear, let me know and I'll try to explain it better.
Second problem: You can get values from tables (there of also Strings) using a Cursor. To get the String you can do something like this where cursor is the Cursor with your result from the database:
String bio;
// Move Cursor to its first element
if(cursor.moveToFirst()) {
// Make sure the cursor is not null
if(cursor != null) {
bio = cursor.getString(cursor.getColumnIndex("Bio")));
}
}
Sidenote: If I read the code correctly, it seems that you use long for ID's? The usual thing to go about ID's is integers as far as I know.