What is the difference between CREATE INDEX AND CREATE UNIQUE INDEX? - android

What is the difference between CREATE INDEX AND CREATE UNIQUE INDEX in SQLite3 used in Android OS? How do indexes work in database? How are they related to columns in the table?

CREATE UNIQUE INDEX isn't just an index : it adds the constraint that all records must have a different value for this column or combination of columns. If you try to insert a record whit the same combination, an error will be raised and prevent the insert (or update).
Use UNIQUE as soon as you're sure you'll have at most one record for some kind of key (user name for example).
EDIT : Here's a link to the documentation of CREATE INDEX, it describes in detail the syntax.

Related

SQLite (Android) : UPDATE query with ORDER BY

Android, SQLite : I want to insert rows in between other rows in myTable using SQLite in android. For this, I am trying to increment ids of the all rows starting say row 3. So that I can insert a new row at position 3.
The primary key of myTable is column id. There are no other constraints in the table.
I have tried using the query mentioned in https://stackoverflow.com/a/9177264/6671004. This query does work in mySQL but not in Android (SQLite)
Here's the line of code :
database.execSQL("UPDATE myTable SET id = (id + 1) where id > 2 ORDER BY id desc");
Here's the error I'm getting on Android Studio (Compile time) :
https://imgur.com/a/9r0iyAa
This is the exception I'm getting if I remove 'ORDER BY id DESC' from the query :
java.lang.RuntimeException: Unable to start activity ComponentInfo{...}: android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: myTable.id (code 1555)
Is this the correct way to do this? Or is there a better way?
As pointed out by many, this is definitely not the correct way to go.
But I found workaround in case someone else is looking for a similar implementation.
Here it is :
UPDATE myTable SET id = - (id + 1) WHERE id > 1;
UPDATE myTable SET id = - id WHERE id < 0;
This is a hack which I found here.
Again, this is not the correct way to go. But just posting a working solution I found.
I have tried using the query mentioned in
https://stackoverflow.com/a/9177264/6671004. This query does work in
mySQL but not in Android (SQLite)
That question is tagged MYSQL. MYSQL has many differences from SQLite.
Here's the line of code :
database.execSQL("UPDATE myTable SET id = (id + 1) where id > 2 ORDER
BY id desc");
The SQLite UPDATE SQL takes the form of :-
i.e. there is no ORDER BY clause and hence the error saying that if you're going to use any KEYWORD then it must be a BETWEEN or IN or a ; (of course you could also extend the condition using AND OR and so on).
This is the exception I'm getting if I remove 'ORDER BY id DESC' from
the query :
The reason being is that the rowid (id being an alias of rowid) has an implied UNIQUE constraint and that the rows will be updated according to the id column in order. So if there are more than 3 rows (or have been and the last row has never been deleted) then when the id is 3, a row with 4 will exist and 3 + 1 = 4 so the row already exists and hence the UNIQUE constraint being encountered.
I want to insert rows in between other rows in myTable using SQLite in
android. For this, I am trying to increment ids of the all rows
starting say row 3. So that I can insert a new row at position 3.
In short that is not a good idea and is virtually definitely not needed.
Is this the correct way to do this? Or is there a better way?
Definitely no
At a guess you want a nice humanly understandable value so you can know what's going on. For example you may present a list with the sequence so you can then say delete the row that has a sequence of 3 and thus equate that to the id column. Fine until you present the list in a different order which may be more user friendly. Suddenly your sequence becomes complicated or even useless and if displayed confusing.
identifiers are intended to identify a row and allow fast access to that row as a numerical index will be more efficient (than a human easily readable non-numeric index) to process. They also cater for reducing unnecessary additional processing (shifting data).
An efficient methodology is presenting the list with tying the id to the position in the list (so position could be the nth element of an array that holds the respective id, regenerating the list (the underlying array) according to a different order so the nth element will still have the respective id).
Embarking on a process of shifting rows will impose additional resource usage for example extra disk IO whose cost is relatively expense. This will be compounded by the fact that you will have to process the rows in reverse order to get around the UNIQUE constraint, that in itself is going to require using even costlier methods because SQLite will by default try to perform the updates efficiently rather than cater for the efficiencies required to digress from recognised/accepted techniques that utilise the underlying efficiencies.
I found this one working. And remove autoincrement from id
String strSQL1 = "UPDATE people_table SET id = (id +1) WHERE id < 0";
String strSQL = "UPDATE people_table SET id = (id -1) WHERE id > 1";
db.execSQL(strSQL);
db.execSQL(strSQL1);

Android - Parse Query - need to know if a string is contained within one of multiple columns in my database table

I have an Android application using parse as a backend. One of my tables in my parse database contains groups of users, one row in this table contains 6 columns of users to form one group.
I would like to return each row where the current user is contained in one of the columns.
My question is what is the most optimum way of achieving this?As it stands I can think of two ways:1. query each row in the groups table and loop through each cloumn looking for the current users username.
2. if possible - use a parse query that says if currenUser equals member 1 or member 2 or member 3 or member 4 or member 5 or member 6. But I don't know if this is possible
Any pointers or help would be appreciated?
For your ParseQuery<ParseObject> query object a whereEqualTo method is available query.whereEqualTo(key, value); try using your column name in place or key and your desired value in in place of value.
Using this you will only get the rows which contains your desired values. It just works as the where clause in SQL qyery. so you will not need to iterate over all the DB entries.

Do we need to create indexes for sqlite tables in android?

As per question..because when I read here
create a indexed column in sqlite
it seems to say that we need to create indexes manually... but when I read here
http://www.android-app-market.com/sqlite-optimization-in-android-programming-sqlite-optimization-in-android-apps.html
it says indexes are created automatically for every unique column.
it says indexes are created automatically for every unique column
No, it says that indexes are created automatically for every UNIQUE column. Here, the author is not using capitalization just to be funny. It is referring to the UNIQUE keyword that can be applied to a column in a CREATE TABLE statement, indicating that all values in the column must be unique compared to all other values in that column.
Most columns in SQL tables are not UNIQUE. For some of those, if you are using them in query constraints, you will want to create indexes.
Indexes are automatically created for unique columns, as in columns that cannot have duplicate values, not "every column." You should still create indexes as necessary depending on how you query your data.

how to store Android database with variable number of attributes per row

For my Android app, I want to save data using sqlite with this format:
name, date, attr1, attr2, attr3,...
These are the requirements:
each date can only contain each name once
there can be a variable number of attributes(numbers) for each name
each specific name has the same number of attributes
The app will be used to track events throughout the day. Events can have zero or more numeric properties.
The questions are: is sqlite the best way to store things here? If so how do I design my database? What other ways are there to store this kind of data?
is sqlite the best way to store things here?
This will depend on a number of other factors, such as how the data will be queried and used, the volume of transactions, data growth and retention, etc. From what you've described, though, SQLite is a great option, offering functionality out-of-the-box that supports some of your requirements directly, and is commonly used in such cases.
If you don't have much experience with relational databases, implementing this functionality may seem difficult at first, but like learning a new language or framework, it will get easier with time.
If so how do I design my database?
Let's step through each of your enumerated requirements...
each date can only contain each name once
SQLite supports the UNIQUE constraint. For example, if your columns were named name and date, you could add the following to your CREATE TABLE statement:
UNIQUE(name, date)
(A more complete CREATE TABLE statement is in the next example below, and it includes this constraint.)
This constraint prevents the insertion of rows with name/date pairs that already exist. Using android.database.sqlite.SQLiteDatabase, if you attempt to insert a row into the table with a duplicate name/date pair, a SQLiteConstraintException will be thrown at runtime. You will need to handle this exception in your java code.
there can be a variable number of attributes(numbers) for each name
This is a textbook case for normalizing the database, putting your data into multiple tables. For example:
CREATE TABLE names (
name_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name TEXT NOT NULL,
date DATETIME,
UNIQUE(name, date));
CREATE TABLE attrs (
name_id INTEGER NOT NULL,
attr_value INTEGER NOT NULL,
FOREIGN KEY(attr_value) REFERENCES names(name_id));
Your queries that retrieve attribute data would then JOIN the two tables. Since you indicated that "Events can have zero or more numeric properties", a LEFT OUTER JOIN might be most appropriate, as it will return names and dates even if there are no attributes.
Here's an example query, by name:
SELECT n.name, n.date, a.attr_value
FROM names AS n
LEFT OUTER JOIN attrs AS a
ON n.name_id = a.name_id
WHERE n.name = 'SMITH'
ORDER BY n.name, n.date, a.attr_value;
This query would return results like the following:
name date attr_value
--------------- ---------- ------------
SMITH 2015-02-13 1027
SMITH 2015-02-13 4426
SMITH 2015-02-13 8390
SMITH 2015-02-20 4426
SMITH 2015-02-20 8152
SMITH 2015-02-20 9328
You can then iterate through and process these results in java. If your results include multiple names and/or dates, then in your loop you should keep track of the last used name and date. If the name/date in the current record is the same, the attribute belongs to the current one. If the name/date is different, then this is a new one.
Note that this approach to your database design is flexible, allowing you to query on the attributes, for instance, to see what name/date pairs are associated.
Also note that there is a FOREIGN KEY constraint on the attrs table, meaning that if you attempt to insert a record into that table with a name_id that does not exist in the names table, a SQLiteConstraintException will be thrown at runtime. You will need to handle this exception in your java code.
each specific name has the same number of attributes
You will need to accommodate this requirement in your java code, probably doing some checks in the database prior to performing an INSERT.
What other ways are there to store this kind of data?
Flat files, JSON, XML, third-party data stores (with their own libraries), to name a few.
I'm not sure but I think the best way to achieve your requirement is to use sqlite and to solve your problem you can have 3 columns only. One for the name and one for the date and the other contains a JSON array that represents the rest of the attributes.

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.

Categories

Resources