Android SQLite ON CONFLICT UPDATE is possible? - android

I need to solve this problem.
I started my project from the wrong concept that ON CONFLICT REPLACE will do an update of the row content when it finds a conflict. Also I was thinking that in that insert (with the conflict) if I don't put a value for a column it wont do the replace but keep the old value. Instead I just discovered that the ON CONFLICT REPLACE if it finds a conflict it will do a delete->insert and if it can't find a value for a column (where I put null for not updating the field) it will replace the null value with the default column value in order to make successfully the insert.
So know I have this big root problem :D
As you understand what I want to reach is this:
I always do the insert, if it finds already a row with the same unique keys (conflict) it will only update the values. If for a field it wont find the values ( I don't put it in the ContentValues ) it wont update those field but keep the old one (like a normal update query where you don't put a column for update it).
To solve my problem I tought these solutions:
ON CONFLICT UPDATE (this will only work when you have only 1 unique
fields, if you have 2 or more unique fields that throw the conflict
it will crash)
UPDATE ON FAIL INSERT where it always try to do an update. If it fails because it can't find the row related to the record (it's not yet present in the db) it will try to do an insert
Some one has already thought about this problem and has a solution?
Or maybe we can just try to find a solution :)
I think that the best way is to keep things on low level (db level) in order to keep a good level of performance.

Following SQLite3 official Documentation is not possible to automatically do a ON CONFLICT UPDATE but only a REPLACE that is like DELETE -> INSERT (new values).

Related

Android-SQLite: How to deal with unique values?

I'm trying to write to a database, in my spec I had to ensure that there are no duplicates for a specific field. Great! I can just make the column unique.
But I have no idea how to deal with that after. If I use the application and accidentally insert a new value which happens to already exist, the app will just crash. How do I check that the value already exists before I try to update the database?
I feel like an if command would work, Buuuuut, How do you scan every value for that column on android anyway?
I assume you propose that we can read all rows in a table, and for each row, check whether the value already exists. If not exist, insert, else, handle conflict.
Another way of doing it is using insertWithOnConflict() method. You can set various conflict resolution strategy such as:
CONFLICT_ABORT
CONFLICT_FAIL
CONFLICT_IGNORE
CONFLICT_NONE
CONFLICT_REPLACE
CONFLICT_ROLLBACK
I don't have any idea on the complexity of this method, but probably it is much better than reading all rows manually and check manually.
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insertWithOnConflict(java.lang.String,%20java.lang.String,%20android.content.ContentValues,%20int)

android sqlite have gap after delete row?

I have 4 EditTexts in dataBase
I delete the second one
The database is numbered 1,3,4
I now want it to be renumbered as 1,2,3.
I looked at many solutions
But I could not find a complete answer..
I do not know what should be in writing
I tried the following code .
But it did not happen
db.delete("SQLITE_SEQUENCE","NAME = ?",new String[]{TABLE_NAME});
Does anyone have the full answer ?
In general, this is poor design for a database. An ID should be consistent for a piece of data, regardless of its peers--it should not fluctuate just because another row was deleted.
That being said, you could always use an UPDATE statement to SET ID = ID-1 WHERE ID > (the ID of the row you deleted). This would work. I don't recommend this approach, but you can.
You can recover this space by executing the SQLite VACUUM command.
Call db.execSQL("VACUUM") after delete

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.

SQL interface like pattern?

I have two tables, SyncedComments and QueuedComments, the latter holds local comments until they are synced with a webserver, when they are synced succesfully they get placed in the synced table, my application should be indifferent to each type. I load in the comments through a CursorLoader, and they may be moved to the synced table while users are reading them. Let's say the user can also edit comments, perhaps while they are being moved, so the application should know where the comment is, regardless of it's table.
To support this, I've thought of having a table with 3 columns, local_id, synced_id and queued_id, the local_id is persistent and simply serves as a reference to either one of the two other id's. When a comment is created a new row is inserted with it's sync_id set to NULL and the queue id it's been given, when a comment is moved then the queue_id is set to NULL and the sync_id is set. This way my application only needs to reference the local id at all times.
How does this solution look? Any flaws? Could it be done smarter?
I would in the first place put all the comments in one table, with flag for whether the comment is synchronized (actually it would probably be ID on server, set to NULL until synchronized and the value obtained from server afterwards). That will take you down to 1 table instead of 3, make it easier to show all comments (because you won't need to do union) and above all avoid problems when the comment is synchronized while being shown, because the comment will not be moving anywhere. And it does less writes to the database file, so it causes less fragmentation and fewer writes to the flash device.

Android Widgets: Where would the 'insert' step for a database occur?

I have a widget that currently takes a random string from an array and sets it to text view on update. The issue here is that the same item can be re-used multiple times in a row due to the string being 'random'
In order to solve this I was going to create a table that held String text, and int viewednum and increment the viewed number each time 'get text' was called. (on update in the widget).
My Question: If I put the insert statements in the widget, won't the data be inserted every time 'on update' is called?
Would it be better for it to go in the DBadapter class somewhere? I'm just unsure about the best way to make sure I don't enter duplicate data. If there is a better alternative like saving a csv file somewhere and using that I'm open to it, it seemed like a sqlite database was the way to go.
Thank you for your time.
That depends on what your onUpdate method does. If each time onUpdate is called it gets a random String from the database, then that would be the place to put it. However, if you are not getting the String during onUpdate, then you should put it in the method where you are accessing your database. I think your confusion is about the purpose of onUpdate. onUpdate doesn't get called every time the user scrolls by the homepage and sees your widget; it gets called regularly on a timescale you specify, and the whole purpose of it is, in a case like yours, to get a new String from the database.
As for your second question, yes, SQlite databases are the way to do it :) I haven't tried saving a csv file or something like that, but I imagine that would be a lot more complex than just using a database.
Declare your database with a UNIQUE constraint on the columns you want to keep unique, then set the desired behaviour via ON CONFLICT in the INSERT statement. ON CONFLICT REPLACE... means the most recent INSERT overwrites. ON CONFLICT IGNORE... keeps the older version.

Categories

Resources