Android SQLite foreign key for 2 tables - android

I am creating Android application, and now I am stuck about proper DB design.
I have 3 tables in my local sqlite db:
BOXES
id
title
NOTES
id
title
content
BOXES_NOTES
id
box_id
element_id
type
Element ID is id for NOTES.id or BOXES.id and now I want to make it as foreign key, so when I delete entry in BOXES or NOTES, I want to update BOXES_NOTES table appropriately. How can I do it?

CREATE TABLE BOXES_NOTES(
ID .... REFERENCES NOTES(ID) ON DELETE /*your constraint*/
BOX_ID ... REFERENCES BOXES(ID) ON DELETE /*your constraint*/
... )
After ON DELETE you can add:
NO ACTION -> You can't delete a box row if there's at least one id into box_notes
CASCADE -> If you delete a box row all boxes_notes rows with that id will be deleted
SET NULL -> If you delete a box row all boxes_notes rows with that id will be set to null (if possible)
What said for ON DELETE is also valid for ON UPDATE.
Remember that using SQLite you have to abilitate foreign keys control. I suggest you to use a SQLiteOpenHelper and override the onOpen method like that:
public void onOpen(SQLiteDatabase db){
super.onOpen(db);
if (!db.isReadOnly()) {
// Enable foreign key constraints
db.execSQL("PRAGMA foreign_keys=ON");
}
}

Nevermind, I redesigned DB a little bit, so now I have only 2 tables:
BOXES
id
title
box_id
NOTES
id
title
content
box_id
Thank you all for answers.

[box_id] INTEGER CONSTRAINT [box_ref] REFERENCES [BOXES]([id]) ON DELETE CASCADE NOT NULL,
[element_id] INTEGER CONSTRAINT [notes_ref] REFERENCES [NOTES]([id]) ON DELETE CASCADE NOT NULL,
since we have cascade delete in both box_id and element_id, any entry in box or in notes deleted will cascade delete entry in this table
suggestion - use proper naming convention
instead of element_id name it notes__id (double underscore normally used to name foreign keys
for all these to work in sqlite one important thing is that we have to enable foreign key constraint at database level which is by default disabled in android
to enable foreign key constraint do the below
db.execSQL("PRAGMA foreign_keys=ON;");

Related

Android SQLite ON UPDATE CASCADE not working when updating a NULL field

During the development of an android application I have noticed that the ON UPDATE CASCADE is not working when a NULL field is updated. However, when the field is a NON NULL value the ON UPDATE CASCADE works just fine.
I searched online but couldn't find a specific answer.
My class extends the SQLiteOpenHelper and I have the override onOpen method where I activate the foreign key constraint. I don't believe this is where the issue lies as it's just not working when updating a NULL field.
#Override
public void onOpen(#Nonnull final SQLiteDatabase db) {
super.onOpen(db);
if (!db.isReadOnly()) {
// Enable foreign key constraints
db.execSQL("PRAGMA foreign_keys=ON;");
}
}
The schema I am using is:
CREATE TABLE IF NOT EXIST users (
role_id INTEGER,
user_id NUMERIC,
username TEXT,
PRIMARY KEY(user_id)
)
CREATE TABLE IF NOT EXIST devices (
user_id NUMERIC,
device_id NUMERIC,
device_name TEXT,
PRIMARY KEY(device_id),
FOREIGN KEY(user_id) REFERENCES users(user_id)
ON UPDATE CASCADE
)
INSERT INTO users (role_id, user_id, username) VALUES (1, NULL, 'test')
INSERT INTO devices (user_id, devices, device_name) VALUES (NULL, NULL, 'test')
When we now update this user row and replace the NULL with 1 the update is not being cascaded to the device row.
Answered by "chue x":
When using NULL in the child table it is not considered related to the parent. NULL is a special value and does not apply to the relationship constraint. Therefore you are allowed to insert rows in the child (using NULL keys) without any rows in the parent. The only way to force a relationship with the parent is to declare the child field as not-nullable.

SQLite Delete Cascade not working

In Android 4.2, using SQLite 3.7.11, when I delete a row from the Quizzes table, who's schema is below, the corresponding rows in the QuizQuestions table are not deleted.
I can't figure out what's wrong. I have tried putting
db.execSQL("PRAGMA foreign_keys = ON;");
before and after the create table statements.
Create table statements:
CREATE TABLE quizzes(quiz_name TEXT PRIMARY KEY COLLATE NOCASE);
CREATE TABLE quizQuestions(quiz_name TEXT, question_id INTEGER,
PRIMARY KEY(quiz_name, question_id),
FOREIGN KEY(quiz_name) REFERENCES quizzes(quiz_name) ON DELETE CASCADE,
FOREIGN KEY(question_id) REFERENCES questions(question_id) ON DELETE CASCADE);
Your database should delete rows from quizQuestions in case someone is deleting from quizzes or from questions. It will ignore the entire foreign key constraint in case foreign key support is turned off and you have just regular columns that can contain any value.
SQLite defaults to PRAGMA foreign_keys = OFF every time you open the database. It's not a property of a table or of the schema.
In case you use SQLiteOpenHelper put it in onOpen. That is the place that is called every time the database is opened. onCreate only once when the database is created.
What SQLiteOpenHelper calls when you call getWriteableDatabase for the first time is
onConfigure every time, API Level >= 16 required
depending on the existence and version of the database file the following is called within an transaction
onCreate if there is no database file. Typically, this happens only once in the entire lifetime of the app.
onUpgrade if the database version (PRAGMA user_version - saved inside the database file) is less then the version supplied in SQLiteOpenHelper's constructor. Happens every time you bump the version in your code.
Nothing if file exists and version matches.
onOpen every time
If the same instance of SQLiteOpenHelper already has an open database it will just return it and nothing of above happens.
Try adding this right after opening database in your Android app:
db.execSQL("PRAGMA foreign_keys=ON");
This turns on support for foreign keys, which is necessary for ON DELETE CASCADE to work properly.
Sqlite disable foreign key constrain by default, so you need to enable it by simply override onOpen method in your DBhelper class like below
public class YourOwnDbHelper extends SQLiteOpenHelper {
#Override
public void onOpen(SQLiteDatabase db){
super.onOpen(db);
db.execSQL("PRAGMA foreign_keys=ON");
}
}
i had the same issue on visual basic!!! you have to write the command text like this:
cone.CommandText = "PRAGMA foreign_keys = ON; DELETE FROM employees
WHERE cod_emp=0;"
and you have to do it everytime you delete something

On delete cascade android 2.2

I have 2 tables:
Table 1- create table table1(_id integer primary key, content text not null );
Table 2- create table table2(_id integer primary key, id_parent integer, content text not null , CONSTRAINT [FK_table2_id_parent] FOREIGN KEY (id_parent) REFERENCES table1 (_id) ON DELETE CASCADE );
But the DELETE CASCADE doesn't do anything... Anyone know what I'm doing wrong?
[EDIT:
When I try to delete rows from table1 I can, but when I look for table2 the records are all there ... even those who have the id_parent that no longer exists from Table1.]
I'm using android 2.2.
First make sure your used create table commands are syntactically and logically right.
If yes then this is due to following:
Declaring and defining foreign key does not apply them really to act.
You need to explicitly on the foreign key constraint in your database.
if (!db.isReadOnly()) {
// Enable foreign key constraints
db.execSQL("PRAGMA foreign_keys=ON;");
}

Conflict resolution in Android's SQLiteDatabase

How does Android's SQLite library resolve conflicts if I insert duplicate rows? I am building my app for API level 7, which unfortunately does not have the SQLiteDatabase.insertOnConflict() method that was included starting in API level 8.
You can specify a UNIQUE index in the table definition which will allow rows to be REPLACED:
CREATE TABLE mytable (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
UNIQUE (id) ON CONFLICT REPLACE
)
If a row an INSERT or UPDATE statement tries to add a row with an id which already exists, the existing row is replaced with the new one.
There's a ON CONFLICT clause in SQLite that you can say INSERT INTO ... ON CONFLICT....
Read the documentation please. http://www.sqlite.org/lang_conflict.html
By default i you have unique index exception will be thrown on duplicated index insert. Common solution is check record existence before execute insert - pseudo-code:
select * from people where name = 'Smith';
//if resultset is empty then perform insert
insert into people values 'Smith'

How to stop parent delete if child present

I want to use constraints in SQLite.
Scenario: Stop parent delete if child is present.
How can I achieve that?
Corrected: SQLite supports foreign key constraints, but they're off by default. You have to enable them at run time with this statement. (That means you can't set this once, and expect it to stick. If you forget to set it just once, you can delete rows from the parent and leave orphans in the child table.)
sqlite> PRAGMA foreign_keys = ON;
Details are at Enabling Foreign Key Support
SQLite can be compiled with foreign key support entirely disabled. That's something to keep in mind.
Lets say you have table A (ID, NAME) and table B (ID, A_ID, NICK_NAME)
When you create table A you'd do
create table A (
ID INTEGER PRIMARY KEY,
NAME TEXT NOT NULL UNIQUE
);
create table B (
ID INTEGER PRIMARY KEY,
A_ID INTEGER NOT NULL,
NICK_NAME TEXT,
CONSTRAINT A_FK FOREIGN KEY (A_ID) REFERENCES A (ID) ON DELETE RESTRICT
);
That should cause an error if you try to delete content from table A that is referenced by column B.
EDIT: as noted in the original poster's comment and my own following it, this apparently does not work. Anyone else shed light on this?

Categories

Resources