Please let me know how to delete n-rows in android sqlite database. I used this code:
String ALTER_TBL ="delete from " + MYDATABASE_TABLE +
"where"+KEY_ID+"in (select top 3"+ KEY_ID +"from"+ MYDATABASE_TABLE+"order by _id );";
sqLiteDatabase.execSQL(ALTER_TBL);
But it shows an error.
03-21 13:19:39.217: INFO/Database(1616): sqlite returned: error code = 1, msg = near "in": syntax error
03-21 13:19:39.226: ERROR/Database(1616): Failure 1 (near "in": syntax error) on 0x23fed8 when preparing 'delete from detail1where_id in (select top 3_idfromdetail1order by _id );'.
String ALTER_TBL ="delete from " + MYDATABASE_TABLE +
" where "+KEY_ID+" in (select "+ KEY_ID +" from "+ MYDATABASE_TABLE+" order by _id LIMIT 3);";
there is no "top 3" command in sqlite I know of, you have to add a limit
watch out for spaces when you add strings together : "delete from" + TABLE + "where" = "delete frommytablewhere"
This approach uses two steps to delete the first N rows.
Find the first N rows:
SELECT id_column FROM table_name ORDER BY id_column LIMIT 3
The result is a list of ids that represent the first N (here: 3) rows. The ORDER BY part is important since SQLite does not guarantee any order without that clause. Without ORDER BY the statement could delete 3 random rows.
Delete any row from the table that matches the list of ids:
DELETE FROM table_name WHERE id_column IN ( {Result of step 1} )
If the result from step 1 is empty nothing will happen, if there are less than N rows just these will be deleted.
It is important to note that the id_column has to be unique, otherwise more than the intended rows will be deleted. In case the column that is used for ordering is not unique the whole statement can be changed to DELETE FROM table_name WHERE unique_column IN (SELECT unique_column FROM table_name ORDER BY sort_column LIMIT 3). Hint: SQLite's ROWID is a good candidate for unique_column when deleting on tables (may not work when deleting on views - not sure here).
To delete the last N rows the sort order has to be reversed to descending (DESC):
DELETE FROM table_name WHERE unique_column IN (
SELECT unique_column FROM table_name ORDER BY sort_column DESC LIMIT 3
)
To delete the Nth to Mth row the LIMIT clause can be extended by an OFFSET. Example below would skip the first 2 rows and return / delete the next 3.
SELECT unique_column FROM table_name ORDER BY sort_column LIMIT 3 OFFSET 2
Setting the LIMIT to a negative value (e.g. LIMIT -1 OFFSET 2) would return all rows besides the first 2 resulting in deletion of everything but the first 2 rows - that could also be accomplished by turning the SELECT .. WHERE .. IN () into SELECT .. WHERE .. NOT IN ()
SQLite has an option to enable the ORDER BY x LIMIT n part directly in the DELETE statement without a sub-query. That option is not enabled on Android and can't be activated but this might be of interest to people using SQLite on other systems:
DELETE FROM table_name ORDER BY sort_column LIMIT 3
It seems that you've missed some spaces:
"where"+KEY_ID+"in..
must be:
"where "+KEY_ID+" in...
Furthermore you need to use the limit statement instead of top:
I'll do:
db.delete(MYDATABASE_TABLE, "KEY_ID > "+ value, null);
you can try this code
int id;
public void deleteRow(int id) {
myDataBase.delete(TABLE_NAME, KEY_ID + "=" + id, null);
}
String id;
public void deleteRow(String id) {
myDataBase.delete(TABLE_NAME, KEY_ID + "=\" " + id+"\"", null);
}
It is a bit long procedure but you can do it like this
first get the ids column of table from which which you want to delete certain values
public Cursor KEY_IDS() {
Cursor mCursor = db.rawQuery("SELECT KEYID " +
" FROM MYDATABASE_TABLE ;", null);
if (mCursor != null)
{
mCursor.moveToFirst();
}
return mCursor;
}
Collect it in an array list
ArrayList<String> first = new ArrayList<String>();
cursor1 = db.KEY_IDS();
cursor1.moveToFirst();
startManagingCursor(cursor1);
for (int i = 0; i < cursor1.getCount(); i++) {
reciv1 = cursor1.getString(cursor1
.getColumnIndex(DBManager.Player_Name));
second.add(reciv1);
}
and the fire delete query
for(int i = 0 ;i<second.size(); i++)
{
db.delete(MYDATABASE_TABLE KEYID +"=" + second.get(i) , null);
}
Delete first N (100) rows in sqlite database
Delete from table WHERE id IN
(SELECT id FROM table limit 100)
You can make use of the following mode: (in addition to the response provided by "zapl").
**DELETE FROM {Table-X} WHERE _ID NOT IN
(SELECT _ID FROM {Table-X} ORDER BY _ID DESC/ASC LIMIT (SELECT {Limit-Column} FROM {SpecificationTable}) );**
Where {Table-X} refers to the table you want to delete, _ID is the main unique-column
DESC/ASC - Based on whether you want to delete the top records or the last records, and finally in the "LIMIT" clause, we provide the "n" factor using another query, which calls in the {Limit-Column} from {SpecificationTable}: Which holds the value against which you want to delete them.
Hope this helps out someone.
Happy Coding.
Related
I am adding a new column to an existing table and adding a new entry to the table with valid data present only in new column (other column being 0 by default)
Adding Column :
final String DB_ADD_COLUMN_STATEMENT_TABLE_SHOP_NAME =
"ALTER TABLE "+ shopName + " ADD COLUMN "+ "D" + time + " FLOAT";
try {
mDB.beginTransaction();
//SQLiteStatement statement = mDB.compileStatement(DB_ADD_COLUMN_STATEMENT_TABLE_SHOP_NAME);
//statement.execute();
mDB.execSQL(DB_ADD_COLUMN_STATEMENT_TABLE_SHOP_NAME);
mDB.setTransactionSuccessful();
}
catch (Exception e) {
Log.d(LOG_TAG,"addItemSample : Exception while adding column to table!!");
}
finally {
mDB.endTransaction();
}
Adding a new entry to the table with data only in this column succeeds.
But when I query the table , this new column doesn't show up in the cursor.
Though the adding column and querying happen in different threads, they are serialized from the way they are being called from my code (ie first column is added and then db is queried) and also the I am using a single connection to db.
I wondering what might be reason for this?
PS:When db query is performed immediately after inserting the column , it shows up.
depends on your query statement.
is it like
String query="select id, column1, column 2 from "+shopName+" where yourcondition";
?
may be you have to add column?
String query="select id, column1, column2, D192200 from "+shopName+"";
or you may query all columns
String query="select * from "+shopName+"";
The issue could be that you are adding a column that expects NOT NULL values
Try something like this:
ALTER TABLE "+ shopName + " ADD COLUMN "+ "D" + time + " FLOAT" default 0 NOT NULL;
Use which ever default value you need and update the values as needed.
Sorry, I'm new. I have a table and need to get the column ID of the first min value of the table. The table is organized so the values keep decreasing until they get to 0 and all subsequent values are equal to zero.
It is possible for none of the values to be zero in which case Id need the last ID. It is important that I only have one return ID because of how I'm implementing it. This is the code I tried first but I'm getting an error.
I did not try to add the exception of there being no 0s here because I thought it might be easier to add an If statement in the implementation of the method I use.
The error I get confuses me because It seems like I can't use FIRST when I thought I could, but here it is:
android.database.sqlite.SQLiteException: no such function: FIRST (code
1): , while compiling: SELECT FIRST (_id) FROM graph WHERE bac = 0;
My code:
public int getWhereZero(){
int zero = 0;
SQLiteDatabase db = getReadableDatabase();
String query = "SELECT FIRST (" + COLUMN_ID
+ ") FROM " + TABLE_GRAPH
+" WHERE " + COLUMN_BAC
+ " = 0;";
Cursor cursor = db.rawQuery(query, null);
if(cursor != null){
cursor.moveToFirst();
zero = cursor.getInt(cursor.getColumnIndex(COLUMN_ID));
cursor.close();
}
return zero;
}
SQLite doesn't have a FIRST() function. However, you can limit the number of rows returned to one using LIMIT, so sorting by the desired order will get the row you need:
SELECT column_id FROM graph ORDER BY bac LIMIT 1;
Okay, so I have a high score table. I have two columns, Player name and score..
Every time a new score is to be added to the table I delete the last row, put the new score and new player name in the last row and then sort the table according to the score.
I can't delete the row with minimum score because there might be multiple entries with the same score and I don't want to delete all of them.
You might want to rebuild your table and include an id column with integer primary key autoincrement. You can do quite a bit with that column in place (here's an SO question you can look into for that).
Anyway I don't know how your process goes and why you need to delete the last row but here's an example of using an ID column to get the last row ( which I assume would be the latest insert and is what usually happens if you declare an ID integer primary key autoincrement column):
public int LastInsert() {
SQLiteDatabase db = this.getReadableDatabase();
final String MY_QUERY = "SELECT MAX(" + colID + ") FROM " + myTable;
Cursor cur = db.rawQuery(MY_QUERY, null);
cur.moveToFirst();
int ID = cur.getInt(0);
cur.close();
return ID;
}
From here you can probably just get the result of LastInsert and use that to direct what your delete function should delete.
Imo you're better of maybe just updating the last row instead of deleting and reinserting in it's place though. Something like this :
public int UpdateAcc(Account acc) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(colName, acc.getName());
cv.put(colScore, acc.getScore());
return db.update(myTable, cv, colID + "=?", new String[]{params});
}
I don't remember rather android with sqlite supports multiple commands per statement, but if so this might work:
DELIMITER ;;
SET #LastId = (SELECT ROWID FROM yourTable ORDER BY ROWID DESC LIMIT 1);;
DELETE FROM yourTable WHERE ROWID=#LastId;;
Otherwise you can store this in a integer variable:
SELECT ROWID FROM yourtable ORDER BY ROWID DESC LIMIT 1;
Then use that variable to run the next line
DELETE FROM yourtable WHERE ROWID=#ThatIntegerHere;
This is my database
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" +
KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
KEY_CATEGORY + " TEXT NOT NULL, " +
KEY_DATE + " TEXT, " +
KEY_PRICE + " LONG, " +
KEY_DETAILS + " TEXT NOT NULL);"
);
and this is the method for deleting all data
public void deleteall() {
// TODO Auto-generated method stub
ourDatabase.delete(DATABASE_TABLE, null, null);
}
and this is the method for deleting a particular data
public void deletentry(long l) {
// TODO Auto-generated method stub
ourDatabase.delete(DATABASE_TABLE, KEY_ROWID + " = " + l,null);
}
Here using the data I deleted but incremented row-id remains there, which I want to reset to 1 as the data is deleted also if I delete a particular data the row-id changes it's value in a sequence manner there should be no gap in between row-id.
I don't think autoincrement is your best option. If your goal is to create a simple numbered table with no gaps, it may be much easier to handle this using a table with a column for you to manually keep up with your ID's.
If you created a table like that, you could then write helper methods in your code for the following operations: addColumn, removeColumn, emptyTable.
Your addColumn method would query the table and determine the max(ID) then add 1 and use that number for the next entry.
Your removeColumn method could remove the entry by ID, then use that ID to resequence everything above it. Or, if order is not important, it could take the last row and re-id it to fill in the gap.
Your emptyTable method could remove all entries.
Update
Maybe this can get you started. The methods would need to be defined in your program. You would have to put the code inside them and then set them up to be called.
For example:
public void addColumn(String category, long date, String details) {
//code here would need to determine the max of ID and add one
//to it. the sql below would retrieve max, i dont know the sql lite code
//off the top of my head.
//SELECT MAX(ID) FROM DATABASE_TABLE;
int newID = max + 1;
//add row to the database using newID
}
public void removeColumn(int id) {
//remove column from database
//DELETE FROM DATABASE_TABLE WHERE ID = id;
//change last entry to use id
//UPDATE DATABASE_TABLE SET ID = id WHERE id = (SELECT MAX(ID) FROM DATABASE_TABLE);
}
public void emptyTable() {
//DELETE FROM DATABASE_TABLE;
}
To call these methods, you would call them like any other java method in your class:
addColumn(12, 'text', (long)100, 'text');
removeColumn(10);
emptyTable();
SQLite keeps the largest ROWID in the special SQLITE_SEQUENCE table. You can delete that table as:
db.delete("SQLITE_SEQUENCE","NAME = ?",new String[]{TABLE_NAME});
Unfortunately, SQLite AUTOINCREMENT is not guaranteed to work as you want. Quoting the docs:
If no ROWID is specified on the insert, or if the specified ROWID has
a value of NULL, then an appropriate ROWID is created automatically.
The usual algorithm is to give the newly created row a ROWID that is
one larger than the largest ROWID in the table prior to the insert. If
the table is initially empty, then a ROWID of 1 is used. If the
largest ROWID is equal to the largest possible integer
(9223372036854775807) then the database engine starts picking positive
candidate ROWIDs at random until it finds one that is not previously
used. If no unused ROWID can be found after a reasonable number of
attempts, the insert operation fails with an SQLITE_FULL error. If no
negative ROWID values are inserted explicitly, then automatically
generated ROWID values will always be greater than zero.
If you need this specific behaviour you described, the only solution would be for you to manually control the KEY_ROWID for your table, making sure you properly account for inserts and deletes.
You can also delete your table from SQLite_Sequence using
sqlDb.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = 'YOUR_TABLE_NAME'");
I create an Android app that has "recents history".
I would like to limit the size of this table to a maximum of 50 rows (according to their insert date).
I saw several threads that talk about limiting the number of deleted rows, but I'm not sure if this feature is even enabled in Android's SQLite.
Can anyone help here?
Thanks
Create a trigger
CREATE TRIGGER delete_till_50 INSERT ON _table WHEN (select count(*) from _table)>50
BEGIN
DELETE FROM _table WHERE _table._id IN (SELECT _table._id FROM _table ORDER BY _table._id limit (select count(*) -50 from _table ));
END;
EDIT:
You can change
DELETE FROM ... WHERE ... IN ...
to
DELETE FROM ... WHERE ... NOT IN ...
as Mojo Risin wrote. I'm not sure about difference of performance for large tables for using IN and NOT IN, but for your problem it's no difference.
I think sql can't manage the number of rows in your table so you'll have to manage it by yourself. You can execute query after data insertion that will reduce the data - something like this should work
DELETE FROM table where _id NOT IN (SELECT _id from table ORDER BY insertion_date DESC LIMIT 50)
Check out SearchRecentSuggestions's source code for an example. It has a method to truncate history up to a given number of entries, using LIMIT -1 OFFSET <maxEntries>. You have to sort the entries by the reversed order of insertion first, then skip the first maxEntries.
If you call this automatically every upon insertion, then you only need to LIMIT 1 as there can never be more than maxEntries + 1 anyway.
/**
* Reduces the length of the history table, to prevent it from growing too large.
*
* #param cr Convenience copy of the content resolver.
* #param maxEntries Max entries to leave in the table. 0 means remove all entries.
*/
protected void truncateHistory(ContentResolver cr, int maxEntries) {
if (maxEntries < 0) {
throw new IllegalArgumentException();
}
try {
// null means "delete all". otherwise "delete but leave n newest"
String selection = null;
if (maxEntries > 0) {
selection = "_id IN " +
"(SELECT _id FROM suggestions" +
" ORDER BY " + SuggestionColumns.DATE + " DESC" +
" LIMIT -1 OFFSET " + String.valueOf(maxEntries) + ")";
}
cr.delete(mSuggestionsUri, selection, null);
} catch (RuntimeException e) {
Log.e(LOG_TAG, "truncateHistory", e);
}
}