I want to use below given delete method from my Database Helper class. I asked this 2 times but not such responses i am getting. This is the handler class which i had taken from androidhive.info
Delete Method ( In DatabaseHandler File ):
// Deleting single contact
public void deleteContact(Contact contact) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_CONTACTS, KEY_ID + " = ?",new String[] { String.valueOf(contact.getID()) });
db.close();
}
When I am implementing it in another activity. like this:
String a = Integer.toString(_contactlist.get(position).getID());
viewHolder.txtid.setText(a.trim());
viewHolder.txt_name.setText(_contactlist.get(position).getName().trim());
viewHolder.txt_phone.setText(_contactlist.get(position).getPhoneNumber().trim());
final int temp = position;
Contact pm = db.getContact(temp); //temp is the position of the contact
db.deleteContact(pm);
but when I am using this i am getting an unexpected error i.e. it is deleting only 1 data in row not the selected data.
My getContact method :
// Getting single contact
Contact getContact(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_CONTACTS, new String[] { KEY_ID,
KEY_NAME, KEY_PH_NO }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
Contact contact = new Contact(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2));
// return contact
return contact;
}
Try giving complete query with where clause. Instead of
db.delete(TABLE_CONTACTS, KEY_ID + " = ?",new String[] { String.valueOf(contact.getID()) });
use
db.execSQL("delete * from TABLE_CONTACTS where KEY_ID = "+contact+";");
Provided, contact should be an integer variable.
but when I am using this i am getting an unexpected error i.e. it is deleting only 1 data in row not the selected data
deleteContact() method will delete only one record from the database as the KEY_ID seems to be unique. Are you expecting more record(s) to be deleted? Or is it deleting wrong record? You may want to put some debug statements in getContact() to check if it retrieving the wrong contact.
I would like to point out a coding problem in getContact() that may not be related to your issue, but still needs to be corrected.
if (cursor != null)
cursor.moveToFirst();
You are checking the null cursor, but there is no guard if it is null and you are still moving ahead to access the cursor. Also you must check null for moveToFirst(), what if the cursor is non-null, but there are no records to read. The app will crash in both cases.
the method deleteContact closes the database handle.
Related
When I started my app years ago, I did some tutorials and always did my queries to the database returning the cursor (without closing it):
public Cursor querySingleId(String szId) {
SQLiteDatabase db = getWritableDatabase();
return db.query(TABLE_ADR, szGetTableEntries, _ID + " = ?", new String[]{szId}, null, null, null);
}
Now I am refactoring my code to MVVM and added models, so I changed my code to this:
public Card querySingleId(String szId) {
SQLiteDatabase db = getWritableDatabase();
Cursor c1 = db.query(TABLE_ADR, szGetTableEntries, _ID + " = ?", new String[]{szId}, null, null, null);
c1.moveToFirst();
return new Card(c1.getString(c1.getColumnIndex(DbHandler.NAME)),
c1.getString(c1.getColumnIndex(DbHandler.STREET)),
c1.getString(c1.getColumnIndex(DbHandler.CITY)));
}
I read that cursors should always be closed (memory leak). Which is the best/most conform approach to return my data from the database? I'm also unsure if there are multiple results, should I stay with a cursor or change to a list?
public List<Card> queryAll() {
SQLiteDatabase db = getWritableDatabase();
Cursor c1 = db.query(TABLE_ADR, szGetTableEntries, null, null, null, null, null);
List<Card> list = new ArrayList<>();
if(c1.moveToFirst()){
do{
list.add(new Card(c1.getString(c1.getColumnIndex(DbHandler.NAME)),
c1.getString(c1.getColumnIndex(DbHandler.STREET)),
c1.getString(c1.getColumnIndex(DbHandler.CITY))));
} while(c1.moveToNext());
}
c1.close();
return list;
}
Is this all just a matter of taste or are there reasons why it should return a cursor or a list/object? Depending where in my code I need the data, a list or a cursor is more convenient.
I'm just not sure what is the correct approach in sqlite queries. There are so many code examples and but it seems most is copy/paste without really digging into the topic.
If the query can return multiple rows then you should return a list.
If you are sure that the query will return just a single Card then returning that single Card would be OK (probably preferable) BUT you should close the Cursor.
However, there isn't an actual requirement/need to do so (e.g. if you your initial activity uses a Cursor for a ListView/Spinner then you may not want to close the Cursor but reuse it and use the adapter's swapCursor when the Activity resumes). The cursor would be effectively closed, as would the database when the App finishes.
As you have used the column _ID which is typically used for a column that is an alias of the rowid column, which is typically generated by SQLite then if used/defined as such (column has been defined explicitly or implicitly as INTEGER PRIMARY KEY with or without AUTOINCREMENT) then it will be a unique value and only return a single row as you have _ID = ?. As such there is a high likeliehood that a single row, or no row would be returned, and unlikely that multiple rows are returned.
So (for a single Card):-
public Card querySingleId(String szId) {
SQLiteDatabase db = getWritableDatabase();
Cursor c1 = db.query(TABLE_ADR, szGetTableEntries, _ID + " = ?", new String[]{szId}, null, null, null);
c1.moveToFirst();
return new Card(c1.getString(c1.getColumnIndex(DbHandler.NAME)),
c1.getString(c1.getColumnIndex(DbHandler.STREET)),
c1.getString(c1.getColumnIndex(DbHandler.CITY)));
}
Should be something like :-
public Card querySingleId(String szId) {
SQLiteDatabase db = getWritableDatabase();
Card rv = null;
Cursor c1 = db.query(TABLE_ADR, szGetTableEntries, _ID + " = ?", new String[]{szId}, null, null, null);
if (c1.moveToFirst()) { //<<<<<< Should always check if the move moved
rv = new Card(c1.getString(c1.getColumnIndex(DbHandler.NAME)),
c1.getString(c1.getColumnIndex(DbHandler.STREET)),
c1.getString(c1.getColumnIndex(DbHandler.CITY)));
}
c1.close();
return rv; //<<<<< Note should check the returned Card for null
}
In addition to memory leaks not closing Cursors can result in a too many open connections (1K (1024) if memory serves correctly) and then a exception: unable to open database file (code 14); as underneath all the wrappers a Cursor has a file associated with it.
I want to get the first name, middle name and last name of a student whose userid is used for login. I have written this particular piece of code but it stops my application.
I have used both the ways like database.query() and .rawquery() also.
Cursor studentData(String userId) {
SQLiteDatabase db = getWritableDatabase();
Cursor cursor = db.query(studentTable, new String[] { "First_Name", "Middle_Name", "Last_Name"}, "User_ID=?", new String[] { userId }, null, null, null, null);
// Cursor cursor = db.rawQuery("select First_Name, Middle_Name, Last_Name from Student_Table where User_ID =?", new String[]{userId});
String data = cursor.getString(cursor.getColumnIndex("First_Name"));
db.close();
return cursor;
}
I should get whole name in the string.
You have a number of issues.
Attempting to use String data = cursor.getString(cursor.getColumnIndex("First_Name"));,
will result in an error because you have not moved the cursor beyond BEFORE THE FIRST ROW and the attempt to access the row -1 will result in an exception (the likely issue you have encountered).
you can use various move??? methods e.g. moveToFirst, moveToNext (the 2 most common), moveToLast, moveToPosition.
Most of the Cursor move??? methods return true if the move could be made, else false.
You CANNOT close the database and then access the Cursor (this would happen if the issue above was resolved)
The Cursor buffers rows and then ONLY when required.
That is The Cursor is when returned from the query method (or rawQuery) at a position of BEFORE THE FIRST ROW (-1), it's only when an attempt is made to move through the Cursor that the CursorWindow (the buffer) is filled (getCount() included) and the actual data obtained. So the database MUST be open.
If you want a single String, the full name, then you could use :-
String studentData(String userId) { //<<<<<<<<<< returns the string rather than the Cursor
SQLiteDatabase db = getWritableDatabase();
String rv = "NO NAME FOUND"; //<<<<<<<<<< value returned if no row is located
Cursor cursor = db.query(studentTable, new String[] { "First_Name", "Middle_Name", "Last_Name"}, "User_ID=?", new String[] { userId }, null, null, null, null);
if (cursor.modeToFirst()) {
String rv =
cursor.getString(cursor.getColumnIndex("First_Name")) +
" " +
cursor.getString(cursor.getColumnIndex("Middle_Name")) +
" " +
cursor.getString(cursor.getColumnIndex("Last_Name"));
}
cursor.close(); //<<<<<<<<<< should close all cursors when done with them
db.close(); //<<<<<<<<<< not required but would result in an exception if returning a Cursor
return rv;
}
Or alternately :-
String studentData(String userId) { //<<<<<<<<<< returns the string rather than the Cursor
SQLiteDatabase db = getWritableDatabase();
String rv = "NO NAME FOUND"; //<<<<<<<<<< value returned if no row is located
Cursor cursor = db.query(studentTable, new String[] { "First_Name"||" "||"Middle_Name"||" "||"Last_Name" AS fullname}, "User_ID=?", new String[] { userId }, null, null, null, null);
if (cursor.modeToFirst()) {
String rv =
cursor.getString(cursor.getColumnIndex("fullname"));
}
cursor.close(); //<<<<<<<<<< should close all cursors when done with them
db.close(); //<<<<<<<<<< not required but would result in an exception if returning a Cursor
return rv;
}
the underlying query being SELECT First_Name||" "||Middle_Name||" "||LastName AS fullname FROM student_table; so you concatenate the names as part of the query which returns just one dynamically created column named fullname.
my app should delete a specific row in the sql database by this method
public void delete(int id){
open();
sqLiteDatabase.delete("item","id = "+id,null);
close();
}
and it should also delete all rows if the user want that by this method
public void deleteAll(){
cursor=sqLiteDatabase.rawQuery("select * from item",null);
cursor.moveToFirst();
i=1;
while (!cursor.isAfterLast()) {
sqLiteDatabase.delete("item","id = "+i,null);
i++;
System.out.println(i);
cursor.moveToNext();
}
}
when the user use deleteAll() alone it is work but when he use it after using delete() it delete all rows before the deleted one using delete()
is the problem in deleteAll() method ? and how to fix it?
Your delete() function only deletes rows with the given id. If you want to delete all rows, then just do
sqLiteDatabase.delete("item", null ,null);
There is no reason to write your own loop especially since you never use the Cursor anyway.
Additionally, you should never use string concatenation for the "where" clause in a SQL statement. Instead use "id = ?" and provide a String[] with the values:
db.delete("image","id= ?", new String[] {id});
Here is an example of how to delete a particular column with an id:
SQLiteDatabase db= this.getWritableDatabase();
db.delete("image","id= ?", new String[] {id});
Toast.makeText(context,"Delete successfully",Toast.LENGTH_LONG).show();
Hope this will work for you
Cursor getting first value as this
But returning last value as this.
Code for getting from cursor
BillInfo getContact(String date) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor query
Cursor cursor = db.query(TABLE_ID, new String[] { KEY_ID,
KEY_NAME, KEY_PRICE, KEY_DATE }, KEY_DATE + "=?",
new String[] { String.valueOf(date) }, null, null, null, null);
BillInfo contact = null ;
Array bill type
BillInfo bill[]=null;
int i=0;
Cursor code
if ( cursor.moveToFirst() ) {
bill=new BillInfo[cursor.getCount()];
do {
//Since both are in different classes
contact = new BillInfo(cursor.getString(0), cursor.getString(1), cursor.getString(2),cursor.getString(3));
bill[i]=contact;
}while(cursor.moveToNext());
}
return bill[i];
}
Code for loading the values on click
public void Load1(View v){
date1=date.getText().toString();
Doubleme d=new Doubleme(this);
BillInfo s;
Returning the value from get contact
s= d.getContact(date1);
info.append( s.toString());
}
Looks like, the value of i is fixed:
int i=0;
But inside of the cursor iteration loop you each time override the bill[i] with a new BillInfo reference. No wonder why the line:
return bill[i];
fetches the last row instead of the first one. I suggest getting rid of the while loop if you only need the first row.
I saved Data in my SQL databank.
Now I want to compare this saved data, with a string
Something like this:
String example = "house";
Now I want to check, if "house" is already in the databank, with a if clause
something like this
if ( example == [SQL Data] ) {
}
else {
}
Now, how can I accomplish this ?
Do something like
String sql = "SELECT * FROM your_table WHERE your_column = '" + example + "'";
Cursor data = database.rawQuery(sql, null);
if (cursor.moveToFirst()) {
// record exists
} else {
// record not found
}
stolen from here
Writing my reply to Sharath's comment as an answer, as the code will be messed up in a comment:
Not saying your reply is wrong, but it's really inefficient to select everything from the table and iterate over it outside the database and it shouldn't be suggested as an answer to the question, because it's a bad habbit to do like that in general.
The way I usually do it, if I want to see if some record is present in the database, I do like this. Not gonna argue about using do-while over a normal while-loop, because that's about different preferences ;)
String query = "SELECT * FROM table_name WHERE column_name=" + the_example_string_to_find;
Cursor cursor = db.rawQuery(query, null);
if(cursor.getCount() > 0) {
cursor.moveToFirst();
while(!cursor.isAfterLast()) {
// Do whatever you like with the result.
cursor.moveToNext();
}
}
// Getting Specific Record by name.
// in DB handler class make this function call it by sending search criteria.
Records getRecord(String name) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, new String[]{KEY_ID, KEY_NAME, KEY_Auth_Name, KEY_B_PRICE}, KEY_ID + "=?",
new String[]{name}, null, null, null,null);
if (cursor.getCount() > 0)
cursor.moveToFirst();
Records Records = new Records(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2),cursor.getString(3));
// return book
return Records;
}
you need to first fetch all the data from the database and next check the data with what you obtained from the database.
Have a look at the link sample database example
suppose you got a cursor object from the database
cursor = db.rawQuery("SELECT yourColumnName FROM "+TABLE_NAME, null);
if(!cursor.moveToFirst()){
}
else{
do {
if(cursor.getString(0).equals(example))
//do something which you want and break
break;
} while (cursor.moveToNext());
}