How to delete nested child using Trigger in SQLite - sql

I need to delete nested items in my table using triggers. I have a folder table, table have a Id and parrentID. For example
ID FolderName ParentID
--------------------------------
1 A Null
2 B 1
3 C 2
4 D 3
If i delete ID 1 then it will be delete all the record 2,3,4 because 1 is a top parent. There is any way?

The documentation says that
[recursion] cannot be used within a CREATE TRIGGER.
However, if you declare the relationship correctly, you can tell the database to delete the children automatically:
CREATE TABLE MyTable(
ID INTEGER PRIMARY KEY,
FolderName TEXT,
ParentID INTEGER REFERENCES MyTable(ID) ON DELETE CASCADE
);

Related

How to create SQL constraint on primary key to make sure it could only be referenced once?

How do I add constraint to guard that a primary key could only be referenced once?(It could be referenced in two tables)
Each reference should have a unique value out of the primary key.
Table A
----------------------
id
1
2
3
4
Table B
----------------------
id a_id (foreign key to table A.id)
1 2
2 3
Table C
----------------------
id a_id (foreign key to table A.id)
1 1
I want something to happen to give error when try to insert a_id = 2 into table C as its used in table B already.
You can use an INSERT, UPDATE trigger on each of the child tables to ensure that the PK of the parent table that is about to be inserted or updated does not already exist in the other child table.
What you are trying to do requires another table D, that will help unify the references to A.
Table D will contain its own primary key ( Id ), a reference to table A with a UNIQUE constraint on it (call it AId ), and a third column (called "RowType") to indicate to which of the child tables (B or C) the row corresponds. You can make this column to be of type int, and assign value "0" for B and "1" for C, for example.
Then in table B you add a foreign key to D.Id, AND another column "BRowType" as foreign key to D.RowType; then you define a constraint on this column, so it can only have the value '0' ( or whatever value you have decided to correspond to this table).
For table C your constraint will limit the values to '1'.
Or course, in order to insert a record into B or C you first need to create a record in D. But once you have a record in B that references a record in D, which in turn links to a record in A, you will no longer be able to create a record in C for the same line in A - because of the UNIQUE constraint on D.AId AND the constraint on C.BRowType.
If I understand the question correctly, it sounds like you need to add a unique constraint on the column of each table that references your primary key.
For example:
Table A
----------------------
id (primary key)
1
2
3
Table B
----------------------
id a_id (foreign key to table A.id)
1 2
2 3
Set the a_id column to be UNIQUE and that way you can ensure that the primary key from Table A is not used twice. You would do that in each table which references A.id
If you want to avoid using triggers, you could create a table X with id and a unique constraint on it.
In each transaction in which you insert a record into B or C you have to insert into X as well. Both insertions will only be possible if not yet in the other table.

SQL trigger INSERT AFTER

I am trying to setup a trigger in phpMyAdmin. have two tables, one parent, one child. Every time a new user in users is created I want to automaticly create a line in the permissions table with the (AI) generated id from users as user_id. (permissions.user_id is a foreigh key of users.id)
users:
id email password
--------------------------------------
1 eric#test.com sdgsdhdfhs
2 john#test.com dfgsdgdfhg
3 mary#test.com plkdfjvjvv
permissions:
index user_id allow_read allow_write allow_delete
-------------------------------------------------------------
1 1 1 0 1
2 2 1 1 1
3 3 0 0 0
I've tried (without success):
INSERT
INTO permissions
(user_id)
VALUES
(IDENT_CURRENT('users'))
and
INSERT
INTO permissions
(user_id)
VALUES
(##IDENTITY)
To access the data of the row that caused a trigger to be executed, you can use NEW and OLD aliases. For INSERT triggers only NEW is available. For DELETE triggers only OLD is available. In UPDATE triggers you can use both. They are used the same way as table aliases (e.g. NEW.id / OLD.id).
Given a parent and a child table as follows:
create table parent_table(
id int auto_increment primary key,
pdata varchar(50)
);
create table child_table(
id int auto_increment primary key,
parent_id int not null,
cdata varchar(50) default '',
foreign key (parent_id) references parent_table(id)
);
To insert a child row when a parent row is inserted:
create trigger insert_parent
after insert on parent_table
for each row
insert into child_table(parent_id)
values (new.id);
To delete all related child rows wehen a parent row is deleted:
create trigger delete_parent
before delete on parent_table
for each row
delete from child_table
where parent_id = old.id;
Demo: http://rextester.com/EOW74217
However a delete trigger is not necessary if you define your foreign key with ON DELETE CASCADE
foreign key (parent_id) references parent_table(id) on delete cascade
All related child rows will be deleted without a trigger when you delete the parent row.
Demo: http://rextester.com/CWB43482

How to update rows of two tables that have foreign key restrictions

I have two tables: one is foreign reference table lets say table a and other one is the data table lets say table b.
Now, when I need to change the data in table b, but I get restricted by table a.
How can I change "rid" in both tables without getting this message?
"ERROR: insert or update on table "table a" violates foreign key
constraint "fk_boo_kid" SQL state: 23503
Detail: Key (kid)=(110) is not present in table "table b".
Example query to update both tables:
UPDATE table b table a SET rid = 110 WHERE rid =1
table b
+-----+-------+-------+
| rid | ride | qunta |
+-----+-------+-------+
| 1 | car | 1 |
| 2 | bike | 1 |
+-----+-------+-------+
table a
+-----+-----+------------+
| kid | rid | date |
+-----+-----+------------+
| 1 | 1 | 20-12-2015 |
| 2 | 2 | 20-12-2015 |
+-----+-----+------------+
In Postgres you can use a writeable CTE to update both tables in a single statement.
Assuming this table setup:
create table a (rid integer primary key, ride text, qunta integer);
create table b (kid integer primary key, rid integer references a, date date);
The CTE would be:
with new_a as (
update a
set rid = 110
where rid = 1
)
update b
set rid = 110
where rid = 1;
As (non-deferrable) foreign keys are evaluated on statement level and both the primary and foreign key are changed in the same statement, this works.
SQLFiddle: http://sqlfiddle.com/#!15/db6d1/1
you can not update/delete primary key in table B, because the primary key is used in table A.
you can delete primary key in table B, IF >>
you must delete the row in table A which is used primary key table B.
you can delete the row in table B
you have to change both manual
SET session_replication_role = 'replica';
UPDATE table a SET rid=110 WHERE rid=1 ;
UPDATE table b SET rid=110 WHERE rid=1 ;
SET session_replication_role = 'origin';
This is too long for a comment.
You should really explain why you want to change ids into something else. Primary keys really should be considered immutable, so they identify rows both within a table and over time.
If you do need to change them for some reason, then define proper foreign key constraints for the tables in question. Then define the foreign keys to be on update cascade. This will "cascade" changes to all affected changes when a primary key changes.

sql query to delete by category

ok guys, may be it's not the best title for my problem. so this is the case
i have 2 table in my database,
Parent table
---------
id name
---------
0 A
1 B
2 C
Child table
-------------------------
id name parent_id
-------------------------
0 child_A 1
1 child_B 0
2 child_C 2
so if record A in parent table deleted, how can i delete all child who have parent_id 0 (A have id 0) ??
i hope you can understand my problem and help me .. :) thanks in adv .. :)
i think i've got the solution, first i try to get all field that not have parent anymore
by this query
SELECT * FROM folders C where NOT EXISTS (select * from folders as A INNER JOIN gis_folders as B on (A.parent_id = B.id) where A.id= C.id )
now i just have to delete all the rows on result from that query .. :)
This is called a cascading delete. When you set up the foreign keys you can specify that child rows are deleted.
See section 4.3 of http://www.sqlite.org/foreignkeys.html for more details.
Do this if you don't have a foreign key set up
DELETE parent, child
FROM parent LEFT JOIN child ON parent.id = child.parent_id
WHERE parent.id = 0
I think the best way is to create a trigger on deleted of parent A
and there you can get the deleted parent id and write query to delete from B
similarly create a trigger on delete of Parent B and there again get id from deleted row and delete all rows from C
Othere way could be create a procedure take a id of parent A as parameter
now writer query like
delete from C where Cid in (select Cid from c where CparentID in (select Bid from B where BparentID = aid))
delete from B where BparentID = aid
delete from A where aid = aid
you can also refere to this
http://msdn.microsoft.com/en-us/library/aa933119%28SQL.80%29.aspx
CREATE TABLE tblparent(
id INTEGER PRIMARY KEY auto_increment,
name VARCHAR(50)
)engine=innodb;
CREATE TABLE tblchild(
id INTEGER PRIMARY KEY auto_increment,
name VARCHAR(50),
parent_id INTEGER,
FOREIGN KEY(parent_id) REFERENCES tblparent(id) ON DELETE CASCADE
)engine=innodb;
In that case, when the parent row is deleted, all the rows on the referenced child table that referred on that id will also deleted.
That is called cascading delete.

Can I use select statement with check constraint

My table is parent-child table where it includes two columns. The first column is ID which is auto number. The other column is ParentID which has the special conditions. If the row is parent the ParentID = 0 otherwise it should be related to a ParentID row. For example:
**ID** | **ParentID**
---------------------
1 0
2 0
3 2
4 [it can be 0 or 1 or 2 NOT 3]
The ParentID depends on the ID column, if the ID includes ParentID = 0 then the ParentID can be that ID.
The question is can i do something like this??
constraint ParentID_ck ckeck(ParentID in(0, select ID from table where ParentID = 0;))
Or I should use other solution such as PL/SQL:
DECLARE
--Somthing..
BEGIN
--Somthing..
END;
And put it inside the check constraint.
You need to implement this constraint with combination of foreign key constraint and a trigger
You may use a null-able foreign key from the table to itself.(parentID == null shows the root nodes).
For the part of select ID from table where ParentID = 0 (null) of the constraint you may use a after insert or update DML trigger, some trigger examples could be found here
You can do something like:
insert into TABLE_NAME(PARENT_ID,ID)
(select <THE_PARENT_ID>, <ID> from DUAL where
exists (select 1 from TABLE_NAME where PARENT_ID = <THE_PARENT_ID>))
So that those PARENT_ID's which are actually not in the TABLE_NAME would not be inserted.
You can do this by fixing your data model first. Your table has two kinds of entities - Parents and Children. Create a separate table for your Parents, then you can use ordinary referential constraints.