SQLite id row not following sequential order after deleting rows - android

I am trying to make a notes taking app and the way I wrote app to delete specific row is in this way -
FIRST - If a user taps on any cardView from a recyclerView, first activity will forwards cardView position using getAdapterPosition().
SECOND - Second activity receives cardView`s positon, to delete a specific row from SQLite database, I called a method known as 'totalNotes()' which will return total number of rows present in SQLite database. Finally, to delete the row I subtract the number received from 'totalNotes()' method with the getAdapterPosition().
PROBLEM - They way I have programmed it only works if the rows in the database are in sequential order. However, when a user wants to delete a row number 3 and 2 from 5 rows, the remaning rows are 1,4 and 5. How can make the database so auto implement sequential order after row deletion?
I have looked on 'almost' similar problem on the site but they fail when I try to implement in my code. I am new to Android development.
[Demo Picture][2]
How can I assign sequential IDs?
How my app looks like

You should not base on the row number sequential. Almost(if not all) all databases have the same behavior on auto-increment field. When you get data from database you need to get also the ID, and to keep the ID inside the APP so when deleting from DB you will delete base on that ID:
id = note.noteID; /// Selected note (noteID) to be deleted.
--------
dbHandler!!.deleteNote(id);
---------
// Here you bind your note to your viewHolder
fun bindItems(note: UserNotes) {
noteTitle.text = note.noteTitle
noteText.text = note.noteText
noteText.noteId = note.noteID;
}

Using sequential Ids is bad, because when you delete a record with Id = 5, the next record you add to your table is not going to be Id = 5 as well, it's going to be Id = 6, so it's going to cause you problems sooner or later.
The way #Simion suggested is:
You ask for all the data, (i.e. all your notes)
When you select a note you ask for the Id of that note, and save it in a variable.
If the user decides to delete that note you should do deleteNote(noteId), that way you can use anything you want as an Id and you don't rely on the Ids being sequential (which is, as I said before, usually a bad idea)

Related

SQLite in Android - How to generate User IDs with date and sequential number per day

I currently have an app where I store user data in a SQLite database, and one of my fields is a User ID. I would like to add an option to auto-generate User IDs in an mmddyyXXX format, where XXX is a sequential number per user that resets every day.
Does anyone know how I would approach this? I looked at some of the other similar questions, but they don't seem to be helpful.
This is not complicated at all. If your'e similar with SQLite in android just take the date and the userId using a SELECT and generate that string yourself.
If the XXX is not the userId just save another table containing 'tokens' for users. every userId would have a 'token'.
Every new day just change the contents of this table.
I believe you could use a TRIGGER that will generate the userid when a row is inserted.
The following may suit :-
CREATE TRIGGER IF NOT EXISTS newuserid AFTER INSERT ON users
BEGIN
UPDATE users SET userid = strftime('%m%d',date('now'))||substr(strftime('%Y',date('now')),3)||
(
SELECT CAST(substr('000',1,3-length(count()+1)) AS TEXT)||CAST((count()+1) AS TEXT)
FROM USERS
WHERE substr(userid,1,6) = strftime('%m%d',date('now'))||substr(strftime('%Y',date('now')),3)
)
WHERE userid IS NULL;
END;
The trigger is named newuserid
userid is the column for the auto-generated id. The above relies upon it being NULL so it cannot be a PRIMARY INDEX.
There is no reliance upon other columns.
Testing
Starting with an empty table :-
Inserting 4 rows using INSERT INTO users VALUES(null,'This is a new user'); results in :-
To check for another date the rows are adjusted from 041018??? to 040918??? as per :-
4 more rows are inserted using INSERT INTO users VALUES(null,'This is a new user');, resulting in :-
Note this answer isn't intended to be fail-safe but rather the basis of the concept for the answer.

SQLite, merging two tables based on higher value in a column

I've got two SQLite databases, each with a table that I need to keep synchronized by merging rows that have the same key. The tables are laid out like this:
CREATE TABLE titles ( name TEXT PRIMARY KEY,
chapter TEXT ,
page INTEGER DEFAULT 1 ,
updated INTEGER DEFAULT 0 );
I want to be able to run the same commands on each of the two tables, with the result that for pairs of rows with the same name, whichever row has the greater value in updated will overwrite the other row completely, and rows which do not have a match are copied across, so both tables are identical when finished.
This is for an Android app, so I could feasibly do the comparisons in Java, but I'd prefer an SQLite solution if possible. I'm not very experienced with SQL, so the more explanation you can give, the more it'll help.
EDIT
To clarify: I need something I can execute at an arbitrary time, to be invoked by other code. One of the two databases is not always present, and may not be completely intact when operations on the other occur, so I don't think a trigger will work.
Assuming that you have attached the other database to your main database:
ATTACH '/some/where/.../the/other/db-file' AS other;
you can first delete all records that are to be overwritten because their updated field is smaller than the corresponding updated field in the other table:
DELETE FROM main.titles
WHERE updated < (SELECT updated
FROM other.titles
WHERE other.titles.name = main.titles.name);
and then copy all newer and missing records:
INSERT INTO main.titles
SELECT * FROM other.titles
WHERE name NOT IN (SELECT name
FROM main.titles);
To update in the other direction, exchange the main/other database names.
For this, you can use a trigger.
i.e.
CREATE TRIGGER sync_trigger
AFTER INSERT OR UPDATE OF updated ON titles
REFERENCING NEW AS n
FOR EACH ROW
DECLARE updated_match;
DECLARE prime_name;
DECLARE max_updated;
BEGIN
SET prime_name = n.name;
ATTACH database2name AS db2;
SELECT updated
INTO updated_match
FROM db2.titles t
WHERE t.name=prime_name)
IF updated_match is not null THEN
IF n.updated > updated_match THEN
SET max_updated=n.updated;
ELSE
SET max_updated=updated_match;
END IF;
UPDATE titles
SET updated=max_updated
WHERE name=prime_name;
UPDATE db2.titles
SET updated=max_updated
WHERE name=prime_name;
END IF;
END sync_trigger;
The syntax may be a little off. I don't use triggers all that often and this is a fairly complex one, but it should give you an idea of where to start at least. You will need to assign this to one database, exchanging "database2name" for the other database's name and then assign it again to the other database, swapping the "database2name" out for the other database.
Hope this helps.

Delete row in sqlite database

I have a sqlite database which store different multiple user's data. I wanted to ask how to delete specific row in the database? I'm not really familiar with database type of stuff. Currently I have a delete function that used to delete one of the user's information in the database. But I'm not really sure how to delete the entire row. (I got emailid, first & last name and ssid in my database. )
public void delete_user(String ssid) {
Log.i(TAG,"delete_user ssid["+ssid+"]...");
String[] valuesWhere = new String[1];
valuesWhere[0] = ssid;
this.getWritableDatabase().delete("user", "ssid=?", valuesWhere);
}
Should I declare every value that I wanted to delete? I wanted to know whether is there another way that able to delete specific row of data. Any comments will be appreciated.
Should I declare every value that I wanted to delete? I wanted to know whether is there another way that able to delete specific row of data.
Your current code will delete every row that matches the ssid passed to delete_user(ssid). If ssid is a unique column (no duplicate values) it will delete one row at most.
But I'm not really sure how to delete the entire row.
Understand that SQLiteDatabase#delete() will never partially delete a row.

ListView row id and position index confusion

I'm just starting to dive into some basic Android development and have been experimenting with a ListView and integrating it with a SimpleCursorAdapter. I look through a lot of online code samples, but I also have a book to use as a reference (Professional Android 2 Application Development).
In the book they work out an example To-Do list application that stores the list items in a SQLite database with an auto-incrementing, integer, primary key field.
A user can create new list items, but can also delete a selected item from the list. In the code, when the delete occurs, the primary key field is restricted (within the WHERE clause of the SQL statement) by the position attribute of the item as opposed to the item's rowid.
To me, this seems like an incorrect implementation. Looking at the SQLite documentation for AUTOINCREMENT, it says that this value will always increase and old values will never be re-used on the same table. So if you're deleting and adding things to the list, it would seem that the position and row id can get out of sync rather quickly.
Am I correct, then, to assume that the row id is the correct way to "index" into the database table and not the list position? I think the position would be safe to use if one is using the regular ListAdapter, but doesn't seem suitable when indexing into the database.
You can use the position to get a cursor to a particular list entry (and this cursor would be the 'row' in the 'table' corresponding to the row id):
Cursor cursor = (Cursor)parent.getItemAtPosition(pos);
int rowCol = c.getColumnIndex("_id");
Then you should see that cursor.getLong(rowCol) == id
That is definitely bad practice. I always use the row id to delete, and use the position id to retrieve the cursor's row id. I have the first edition of that book at home, I'm going to take a look at it myself later.

autoincrement & decrement integer field are available in sqlite database?

I am fetching my data with id which is Integer primary key or integer.
But after deleting any row...
After that if we make select query to show all.
But it will give force close because one id is missing.
I want that id can itself take auto increment & decrement.
when i delete a record at the end(i.g. id=7) after this i add a row then id must be 7 not 8. as same when i delete a row in middle(i.g. id=3) then all the row auto specify by acceding.
your idea can help me.
Most systems with auto-incrementing columns keep track of the last value inserted (or the next one to be inserted) and do not ever reissue a number (give the same number twice), even if the last number issued has been removed from the table.
Judging from what you are asking, SQLite is another such system.
If there is any concurrency in the system, then this is risky, but for a single-user, single-app-at-a-time system, you might get away with:
SELECT MAX(id_column) + 1 FROM YourTable
to find the next available value. Depending on how SQLite behaves, you might be able to embed that in the VALUES list of an INSERT statement:
INSERT INTO YourTable(id_column, ...)
VALUES((SELECT MAX(id_column) + 1 FROM YourTable), ...);
That may not work; you may have to do this as two operations. Note that if there is any concurrency, the two statement form is a bad ideaTM. The primary key unique constraint normally prevents disaster, but one of two concurrent statements fails because it tries to insert a value that the other just inserted - so it has to retry and hope for the best. Clearly, a cell phone has less concurrency than, say, a web server so the problem is correspondingly less severe. But be careful.
On the whole, though, it is best to let gaps appear in the sequence without worrying about it. It is usually not necessary to worry about them. If you must worry about gaps, don't let people make them in the first place. Or move an existing row to fill in the gap when you do a delete that creates one. That still leaves deletes at the end creating gaps when new rows are added, which is why it is best to get over the "it must be a contiguous sequence of numbers" mentality. Auto-increment guarantees uniqueness; it does not guarantee contiguity.

Categories

Resources