I am trying to develop a mobile application to get familiar with SQLite database. In here create, add methods are working. But when I am going to delete in list view the mobile app crashes. Here is the code that I have written.
In MainActivity.java
lv_customerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
CustomerModel clickedCustomer = (CustomerModel) parent.getItemAtPosition(position);
dataBaseHelper.deleteOne(clickedCustomer);
extracted(dataBaseHelper);
Toast.makeText(MainActivity.this, "Deleted" ,Toast.LENGTH_SHORT).show();
}
});
}
private void extracted(DataBaseHelper dataBaseHelper) {
customerArrayAdapter = new ArrayAdapter<CustomerModel>(MainActivity.this, android.R.layout.simple_list_item_1, dataBaseHelper.getEveryone());
lv_customerList.setAdapter(customerArrayAdapter);
}
}
In databaseHelper.java class
`
public boolean deleteOne(CustomerModel customerModel){
SQLiteDatabase db = this.getWritableDatabase();
String queryString = "DELETE FROM" + CUSTOMER_TABLE + " WHERE " + COLUMN_ID + " = " + customerModel.getId();
Cursor cursor = db.rawQuery(queryString, null);
if(cursor.moveToFirst()){
return true;
}else {
return false;
}
}
You have omitted a space between the keyword FROM
and the table name and thus will encounter an exception along the lines of:-
android.database.sqlite.SQLiteException: near "FROMcustomer": syntax error (code 1 SQLITE_ERROR): , while compiling: DELETE FROMcustomer WHERE _id = 9999
HOWEVER, you would then ALWAYS encounter a returned result of false from the DeleteOne
method (see Demo below).
This is due to a two-fold issue a) that the rawQuery
method should ONLY be used for returning data that is extracted as an output SQL statement i.e. a SELECT statement or some PRAGMA statements and b) that other statements such as DELETE do not return anything and actually result in a rollback undoing what they have done.
Instead you should either use:-
an execSQL
method, which again does not return a result,
exeSQL
does what is to be done, which may be nothing, or it fails, orthe respective convenience method, e.g. the delete
method for a deletion.
the convenience methods, in addition to undertaking the action, do return an appropriate result:-
insert
method returns the rowid or alias thereof for ROWID tablesdelete
and update
methods return the number of affected rows (number of rows delete or updated).i.e. the convenience methods invoke the appropriate SQLite API function AFTER the execution to return the value
Demo
The following is a demonstration of:-
execSQL
method and then returning a useful result, anddelete
convenience methodThe following is the DatabaseHelper class used for the Demo that is based upon what can be ascertained from your code:-
class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "the_database";
public static final int DATABASE_VERSION = 1;
public static final String CUSTOMER_TABLE = "customer";
public static final String COLUMN_ID = BaseColumns._ID;
public static final String COLUMN_WHATEVER = "_whatever";
private DatabaseHelper(Context context) {
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
private static volatile DatabaseHelper instance;
public static DatabaseHelper getInstance(Context context) {
if (instance==null) {
instance = new DatabaseHelper(context);
}
return instance;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + CUSTOMER_TABLE +"(" +
COLUMN_ID + " INTEGER PRIMARY KEY" +
"," + COLUMN_WHATEVER + " TEXT" +
");"
);
}
@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
}
public boolean deleteOne(/*CustomerModel customerModel*/ long id){
SQLiteDatabase db = this.getWritableDatabase();
String queryString = "DELETE FROM " + CUSTOMER_TABLE + " WHERE " + COLUMN_ID + " = " + /*customerModel.getId()*/ + id;
Cursor cursor = db.rawQuery(queryString, null);
if(cursor.moveToFirst()){
return true;
}else {
return false;
}
}
/* Using EXECSQL to return result */
public long DeleteByExecSQL(long id) {
SQLiteDatabase db = this.getWritableDatabase();
long beforeDeletionCount, afterDeletionCount;
db.beginTransaction();
beforeDeletionCount = getTableRowCount(CUSTOMER_TABLE,db);
db.execSQL("DELETE FROM " + CUSTOMER_TABLE + " WHERE " + COLUMN_ID + "=?",new String[]{String.valueOf(id)});
afterDeletionCount = getTableRowCount(CUSTOMER_TABLE,db);
db.setTransactionSuccessful();
db.endTransaction();
return beforeDeletionCount - afterDeletionCount;
}
/* Using Convenience DELETE */
public long DeleteViaConvenienceMethod(long id) {
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(CUSTOMER_TABLE,COLUMN_ID+"=?",new String[]{String.valueOf(id)});
}
/* method to get the number of rows in the table */
public long getTableRowCount(String table, SQLiteDatabase db) {
long rv=0;
if (db == null) {
db = this.getWritableDatabase();
}
Cursor csr = db.query(table,new String[]{"count(*)"},null,null,null,null,null);
if (csr.moveToFirst()) rv = csr.getLong(0);
csr.close();
return rv;
}
/* Insert using the convenience INSERT method (returns rowid or alias thereof of inserted row) */
public long insertCustomer(Long id, String whatever) {
ContentValues cv = new ContentValues();
if (id!=null) cv.put(COLUMN_ID,id);
cv.put(COLUMN_WHATEVER,whatever);
return this.getWritableDatabase().insert(CUSTOMER_TABLE,null,cv);
}
/* for generated id */
public long insertCustomer(String whatever) {
return insertCustomer(null,whatever);
}
}
deleteOne
methoddeleteByExecSQL
method, which uses the execSQL method to undertake the deletion but also returns the number of rows that have been deleted by interrogating the number of rows in the table before and after the actual deletion and calculating the difference.deleteViaConvenienceMethod
To actually demonstrate the 3 approaches, the following Activity code:-
public class MainActivity extends AppCompatActivity {
DatabaseHelper dbh;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbh = DatabaseHelper.getInstance(this);
dbh.insertCustomer("C1");
dbh.insertCustomer("C2");
dbh.insertCustomer(100L,"C3");
dbh.insertCustomer("C4");
dbh.insertCustomer("C5");
try {
Log.d("DBINFO_DLT1_1","DELETED=" + dbh.deleteOne(9999));
Log.d("DBINFO_DLTE_1","DELETED=" + dbh.deleteByExecSQL(9999));
Log.d("DBINFO_DLTC_1","DELETED=" + dbh.deleteViaConvenienceMethod(9999));
Log.d("DBINFO_DLT1_2","DELETED="+dbh.deleteOne(100));
dbh.insertCustomer(100L,"C3");
Log.d("DBINFO_DLTE_2","DELETED=" + dbh.deleteByExecSQL(100));
dbh.insertCustomer(100L,"C3");
Log.d("DBINFO_DLTC_2","DELETED=" + dbh.deleteViaConvenienceMethod(100));
} catch (SQLiteException e) {
e.printStackTrace();
}
}
}
When run then the results are:-
2023-11-19 12:20:27.995 D/DBINFO_DLT1_1: DELETED=false
2023-11-19 12:20:27.997 D/DBINFO_DLTE_1: DELETED=0
2023-11-19 12:20:27.997 D/DBINFO_DLTC_1: DELETED=0
2023-11-19 12:20:27.998 D/DBINFO_DLT1_2: DELETED=false
2023-11-19 12:20:28.000 D/DBINFO_DLTE_2: DELETED=1
2023-11-19 12:20:28.001 D/DBINFO_DLTC_2: DELETED=1
delete
method is simpler and more efficient (it uses the the appropriate SQLite interface) and does not rescan the table to get the count
It is suggested that you refer to https://developer.android.com/studio/debug, this would have enabled you to ascertain the initial issue.