Delete From in delete after trigger not deleting from another table - mysql

I am trying to make a DELETE TRIGGER so that when a row is deleted from a table Bike it will delete a row in another table called Available as long as it is not in a different table called in Rental. If it is in Rental table then it will cancel the delete (if that's possible I'm very new to sql).
BEGIN
DELETE FROM Available
Where old.bnumber = Available.bnumber;
END
right now I am getting
1451: Cannot delete or update a parent row: a foreign key constraint
fails (cecs535project.available, CONSTRAINT bnumber FOREIGN KEY
(bnumber) REFERENCES bike (bnumber))
bnumber is a foreign key in Available that references Bike.
Any help is appreciated.
CREATE TABLE `Bike` (
`bnumber` int NOT NULL,
`make` varchar(64) DEFAULT NULL,
`color` varchar(8) DEFAULT NULL,
`year` int DEFAULT NULL,
PRIMARY KEY (`bnumber`)
)
CREATE TABLE `Available` (
`bnumber` int NOT NULL,
`rack-id` int DEFAULT NULL,
PRIMARY KEY (`bnumber`),
KEY `bnumber_idx` (`rack-id`),
KEY `bnumber_idx1` (`bnumber`),
CONSTRAINT `bnumber` FOREIGN KEY (`bnumber`) REFERENCES `Bike` (`bnumber`),
CONSTRAINT `rack-id` FOREIGN KEY (`rack-id`) REFERENCES `Rack` (`id`)
)
CREATE TABLE `Rental` (
`date` date NOT NULL,
`time` time NOT NULL,
`bnumber` int NOT NULL,
`cust-id` int NOT NULL,
`src` int DEFAULT NULL,
PRIMARY KEY (`bnumber`,`cust-id`,`date`,`time`),
KEY `bnumber_idx` (`bnumber`),
KEY `cust-id_idx` (`cust-id`),
KEY `src_idx` (`src`),
CONSTRAINT `bike` FOREIGN KEY (`bnumber`) REFERENCES `Bike` (`bnumber`),
CONSTRAINT `cust-id` FOREIGN KEY (`cust-id`) REFERENCES `Customer` (`id`),
CONSTRAINT `src` FOREIGN KEY (`src`) REFERENCES `Rack` (`id`)
)

I am not a big fan of your current design, and I think it can be simplified. Consider just having a single table for all bike assets, with one column maintaining whether or not it be currently rented out, e.g.
Bike
id | name | type | rented (bit)
1 | bike1 | road | 1
2 | bike2 | mountain | 0
...
Now to record a bike being rented or not, you simply have to update the rented bit column above. Should you want to delete from your inventory, refraining from doing so if the bike be on loan, you can use:
DELETE
FROM Bike
WHERE rented = 0; -- AND your other conditions here

2 possible approaches
Use signal to identify where rental exists an throw an error https://dev.mysql.com/doc/refman/8.0/en/signal.html
test for rental existence in delete;
In both a before trigger is used since the constraint test occurs before an after trigger fires.
DROP TABLE IF EXISTS AVAILABLE;
drop table if exists rental;
drop table if exists BIKE;
CREATE TABLE `Bike` (
`bnumber` int NOT NULL,
`make` varchar(64) DEFAULT NULL,
`color` varchar(8) DEFAULT NULL,
`year` int DEFAULT NULL,
PRIMARY KEY (`bnumber`)
);
insert into bike values
(10,'aaa','red',2020),(20,'bbb','yell',2020);
CREATE TABLE `Available` (
`bnumber` int NOT NULL,
`rack-id` int DEFAULT NULL,
PRIMARY KEY (`bnumber`),
KEY `bnumber_idx` (`rack-id`),
KEY `bnumber_idx1` (`bnumber`),
CONSTRAINT `bnumber` FOREIGN KEY (`bnumber`) REFERENCES `Bike` (`bnumber`)#,
#CONSTRAINT `rack-id` FOREIGN KEY (`rack-id`) REFERENCES `Rack` (`id`)
) ;
insert into available values
(10,100),(20,200);
CREATE TABLE `Rental` (
#`date` date NOT NULL,
#`time` time NOT NULL,
`bnumber` int NOT NULL,
#`cust-id` int NOT NULL,
#`src` int DEFAULT NULL,
#PRIMARY KEY (`bnumber`,`cust-id`,`date`,`time`),
KEY `bnumber_idx` (`bnumber`),
#KEY `cust-id_idx` (`cust-id`),
#KEY `src_idx` (`src`),
CONSTRAINT `bike` FOREIGN KEY (`bnumber`) REFERENCES `Bike` (`bnumber`)#,
#CONSTRAINT `cust-id` FOREIGN KEY (`cust-id`) REFERENCES `Customer` (`id`),
#CONSTRAINT `src` FOREIGN KEY (`src`) REFERENCES `Rack` (`id`)
) ;
insert into rental values
(10);
Approach 1
drop trigger if exists t;
delimiter $$
create trigger t before delete on bike
for each row
begin
if exists (select 1 from rental r where r.bnumber = old.bnumber) then
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'An error occurred Rental exists';
end if;
delete a from available a where a.bnumber = old.bnumber;
end $$
delimiter ;
delete b from bike b;
ERROR 1644 (45000): An error occurred Rental exists
+---------+------+-------+------+
| bnumber | make | color | year |
+---------+------+-------+------+
| 10 | aaa | red | 2020 |
| 20 | bbb | yell | 2020 |
+---------+------+-------+------+
2 rows in set (0.001 sec)
select * from available;
+---------+---------+
| bnumber | rack-id |
+---------+---------+
| 10 | 100 |
| 20 | 200 |
+---------+---------+
2 rows in set (0.001 sec)
select * from rental;
+---------+
| bnumber |
+---------+
| 10 |
+---------+
1 row in set (0.001 sec)
Approach 2
drop trigger if exists t;
delimiter $$
create trigger t before delete on bike
for each row
begin
delete a from available a where a.bnumber = old.bnumber;
end $$
delimiter ;
delete b from bike b where
#bnumber = 10 and
not exists(select 1 from rental r where r.bnumber = b.bnumber);
select * from bike;
+---------+------+-------+------+
| bnumber | make | color | year |
+---------+------+-------+------+
| 10 | aaa | red | 2020 |
+---------+------+-------+------+
1 row in set (0.001 sec)
select * from available;
+---------+---------+
| bnumber | rack-id |
+---------+---------+
| 10 | 100 |
+---------+---------+
1 row in set (0.001 sec)
select * from rental;
+---------+
| bnumber |
+---------+
| 10 |
+---------+
1 row in set (0.001 sec)

Creating an AFTER DELETE instead could also help to skip the Foreign Key Constraint issue
CREATE TRIGGER trigger_name
AFTER DELETE
ON table_name FOR EACH ROW
trigger_body;
ref: https://www.mysqltutorial.org/mysql-triggers/mysql-after-delete-trigger/

Related

How to do this with foreign keys?

I have a table called categories, with the following fields:
id (primary key, identifies the categories)
user_id (foreign key, users.id, the creator of the current category)
category_id (foreign key, categories.id, the id of the parent category id)
Inside this table I have some records that are accessible to everyone.
For these records, both the user_id and the category_id fields are NULL.
In addition, users can create their own records (where the user_id field is not NULL), but every user can access only those that he has made himself.
Each record must meet these conditions:
user_id values must be valid
if the category_id is given then it must be a valid categories.id and that record must be created by the given user
the value of the category_id can be a categoies.id where the user_id is NULL
How can I do this? I think I need more foreign keys for this, but not sure how to do it.
Some examples that may help you to understand my problem:
Lets say I have the following records inside the categories table:
+--------+-------------+-----------------+
| id | user_id | category_id |
+--------+-------------+-----------------+
| 1 | NULL | NULL |
+--------+-------------+-----------------+
| 2 | NULL | NULL |
+--------+-------------+-----------------+
| 3 | 1 | 1 |
+--------+-------------+-----------------+
| 4 | 2 | 1 |
+--------+-------------+-----------------+
and lets say that I want to insert these records:
+-------------+-----------------+----------------------------------------------------------------+
| user_id | category_id | is it insertable?
+-------------+-----------------+----------------------------------------------------------------+
| 1 | NULL | yes, because the value of the user_id is valid id |
+-------------+-----------------+----------------------------------------------------------------+
| 1 | 1 | yes, because the record with id of 1 is created by NULL |
+-------------+-----------------+----------------------------------------------------------------+
| 1 | 3 | yes, because the record with id of 3 is created by user #1 |
+-------------+-----------------+----------------------------------------------------------------+
| 1 | 4 | no, because the record with id of 4 is created by another user |
+-------------+-----------------+----------------------------------------------------------------+
Categories table:
CREATE TABLE `categories` (
`id` int(11) NOT NULL,
`user_id` int(11) DEFAULT NULL,
`category_id` int(11) DEFAULT NULL,
`name` varchar(150) NOT NULL,
`type` enum('income','expense') NOT NULL DEFAULT 'income',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `categories`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `category_id` (`category_id`,`user_id`,`name`),
ADD KEY `user_id` (`user_id`);
ALTER TABLE `categories`
ADD CONSTRAINT `categories_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `categories_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
Unfortunately, MySQL foreign keys can go so far. This is a bit of advanced logic. Might I recommend using a MySQL trigger?
DELIMITER $$
CREATE PROCEDURE `check_categories_user_id`(IN p_category_id INT(11), IN p_user_id INT(11))
BEGIN
IF (p_category_id IS NOT NULL) THEN
SET #other_user_id = (SELECT user_id
FROM categories
WHERE id = p_category_id);
IF (p_user_id <> #other_user_id) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'check constraint on categories.user_id failed';
END IF;
END IF;
END$$
CREATE TRIGGER `categories_before_update` BEFORE UPDATE ON `categories`
FOR EACH ROW
BEGIN
CALL check_categories_user_id(new.category_id, new.user_id);
END$$
CREATE TRIGGER `categories_before_insert` BEFORE INSERT ON `categories`
FOR EACH ROW
BEGIN
CALL check_categories_user_id(new.category_id, new.user_id);
END$$
DELIMITER ;
See dbfiddle here. (If you remove the last INSERT query, the SELECT query works as expected)
Additionally, to avoid some overhead (The SELECT query in the trigger), you can just enforce NULL on user_id when category_id IS NOT NULL (Using triggers like above). If category_id is NOT NULL, you'll just fetch the user_id from the parent row (Or the root row (parent's parent row...etc), if nested).

how to join tables with generalization

I'm having trouble performing a JOIN on tables the problem is this:
In a report cart system I have users, such as students, parents and school employees. I need to generate an SQL statement that when I enter the access ID of the parents it lists all students related to parents ID
Follow the Model:
Is this the best way to implement this "Generalization" and this relationship between parents and students, since they are all users? Can someone help me?
SQL code:
-- -----------------------------------------------------
-- Table `testeboletim`.`type_user`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `testeboletim`.`type_user` (
`idtype_user` INT NOT NULL AUTO_INCREMENT,
`role` VARCHAR(45) NULL,
PRIMARY KEY (`idtype_user`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `testeboletim`.`user`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `testeboletim`.`user` (
`iduser` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NULL,
`ID` VARCHAR(20) NULL,
`birth` DATE NULL,
`telephone` VARCHAR(20) NULL,
`phone` VARCHAR(20) NULL,
`email` VARCHAR(45) NULL,
`type_user_idtype_user` INT NOT NULL,
PRIMARY KEY (`iduser`, `type_user_idtype_user`),
INDEX `fk_usuario_tipo_usuario_idx` (`type_user_idtype_user` ASC),
CONSTRAINT `fk_usuario_tipo_usuario`
FOREIGN KEY (`type_user_idtype_user`)
REFERENCES `testeboletim`.`type_user` (`idtype_user`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `testeboletim`.`student`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `testeboletim`.`student` (
`idstudent` INT NOT NULL AUTO_INCREMENT,
`user_iduser` INT NOT NULL,
`user_type_user_idtype_user` INT NOT NULL,
PRIMARY KEY (`idstudent`, `user_iduser`, `user_type_user_idtype_user`),
INDEX `fk_aluno_usuario1_idx` (`user_iduser` ASC, `user_type_user_idtype_user` ASC),
CONSTRAINT `fk_aluno_usuario1`
FOREIGN KEY (`user_iduser` , `user_type_user_idtype_user`)
REFERENCES `testeboletim`.`user` (`iduser` , `type_user_idtype_user`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `testeboletim`.`parents`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `testeboletim`.`parents` (
`idparents` INT NOT NULL AUTO_INCREMENT,
`user_iduser` INT NOT NULL,
`user_type_user_idtype_user` INT NOT NULL,
PRIMARY KEY (`idparents`, `user_iduser`, `user_type_user_idtype_user`),
INDEX `fk_responsavel_usuario1_idx` (`user_iduser` ASC, `user_type_user_idtype_user` ASC),
CONSTRAINT `fk_responsavel_usuario1`
FOREIGN KEY (`user_iduser` , `user_type_user_idtype_user`)
REFERENCES `testeboletim`.`user` (`iduser` , `type_user_idtype_user`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `testeboletim`.`student_has_parents`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `testeboletim`.`student_has_parents` (
`student_idstudent` INT NOT NULL,
`student_user_iduser` INT NOT NULL,
`parents_idparents` INT NOT NULL,
`parents_user_iduser` INT NOT NULL,
PRIMARY KEY (`student_idstudent`, `student_user_iduser`, `parents_idparents`, `parents_user_iduser`),
INDEX `fk_aluno_has_responsavel_responsavel1_idx` (`parents_idparents` ASC, `parents_user_iduser` ASC),
INDEX `fk_aluno_has_responsavel_aluno1_idx` (`student_idstudent` ASC, `student_user_iduser` ASC),
CONSTRAINT `fk_aluno_has_responsavel_aluno1`
FOREIGN KEY (`student_idstudent` , `student_user_iduser`)
REFERENCES `testeboletim`.`student` (`idstudent` , `user_iduser`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_aluno_has_responsavel_responsavel1`
FOREIGN KEY (`parents_idparents` , `parents_user_iduser`)
REFERENCES `testeboletim`.`parents` (`idparents` , `user_iduser`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
In order to solve this problem, we would need to look at testeboletim.student, testeboletim.parents, and either testeboletim.student_has_parents or testeboletim.user. I have decided to solve your problem using testeboletim.user, because it was clearer in terms of refrence keys, and what not.
Solution using testeboletim.user
Based on your question, we are looking for all rows in testeboletim.student, that have a corresponding iduser testeboletim.user based on the user_iduser of testeboletim.parents.
-- SQL Definition:
SELECT * FROM `testeboletim`.`student` WHERE `user_iduser` IN
(SELECT DISTINCT(`iduser`) FROM `testeboletim`.`user` WHERE `iduser` IN
(SELECT DISTINCT(`user_iduser`) FROM `testeboletim`.`parents`)
);
Now to do the same thing with JOIN, would require the use of LEFT JOIN; in this case testeboletim.student.
SELECT * FROM `testeboletim`.`student` AS `student`
LEFT JOIN `testeboletim`.`user` AS `user`
ON `student`.`user_iduser` = `user`.`iduser`
LEFT JOIN `testeboletim`.`parents` AS `parents`
ON `user`.`iduser` = `parents`.`user_iduser`;
Since I don't have any values, I'm going to share with you the explanation, in order to "prove" that the query works.
mysql> SELECT * FROM `testeboletim`.`student` AS `student`
-> LEFT JOIN `testeboletim`.`user` AS `user`
-> ON `student`.`user_iduser` = `user`.`iduser`
-> LEFT JOIN `testeboletim`.`parents` AS `parents`
-> ON `user`.`iduser` = `parents`.`user_iduser`;
Empty set (0.01 sec)
mysql> EXPLAIN SELECT * FROM `testeboletim`.`student` AS `student`
-> LEFT JOIN `testeboletim`.`user` AS `user`
-> ON `student`.`user_iduser` = `user`.`iduser`
-> LEFT JOIN `testeboletim`.`parents` AS `parents`
-> ON `user`.`iduser` = `parents`.`user_iduser`;
+------+-------------+---------+-------+-----------------------------+-----------------------------+---------+--------------------------+------+-------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+-------+-----------------------------+-----------------------------+---------+--------------------------+------+-------------------------------------------------+
| 1 | SIMPLE | student | index | NULL | PRIMARY | 12 | NULL | 1 | Using index |
| 1 | SIMPLE | user | ALL | PRIMARY | NULL | NULL | NULL | 1 | Using where; Using join buffer (flat, BNL join) |
| 1 | SIMPLE | parents | ref | fk_responsavel_usuario1_idx | fk_responsavel_usuario1_idx | 4 | testeboletim.user.iduser | 1 | Using where; Using index |
+------+-------------+---------+-------+-----------------------------+-----------------------------+---------+--------------------------+------+-------------------------------------------------+
3 rows in set (0.00 sec)

MySQL recursive procedure to delete a record

I have a table, Models that consists of these (relevant) attributes:
-- -----------------------------------------------------
-- Table `someDB`.`Models`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `someDB`.`Models` (
`model_id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
`type_id` SMALLINT UNSIGNED NOT NULL,
-- someOtherAttributes
PRIMARY KEY (`model_id`),
ENGINE = InnoDB;
+---------+---------+
| model_id| type_id |
+---------+---------+
| 1 | 4 |
| 2 | 4 |
| 3 | 5 |
| 4 | 3 |
+---------+---------+
And table Model_Hierarchy that shows the parent & child relationship (again, showing only the relevant attributes):
-- -----------------------------------------------------
-- Table `someDB`.`Model_Hierarchy`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `someDB`.`Model_Hierarchy` (
`parent_id` MEDIUMINT UNSIGNED NOT NULL,
`child_id` MEDIUMINT UNSIGNED NOT NULL,
-- someOtherAttributes,
INDEX `fk_Model_Hierarchy_Models1_idx` (`parent_id` ASC),
INDEX `fk_Model_Hierarchy_Models2_idx` (`child_id` ASC),
PRIMARY KEY (`parent_id`, `child_id`),
CONSTRAINT `fk_Model_Hierarchy_Models1`
FOREIGN KEY (`parent_id`)
REFERENCES `someDB`.`Models` (`model_id`)
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT `fk_Model_Hierarchy_Models2`
FOREIGN KEY (`child_id`)
REFERENCES `someDB`.`Models` (`model_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
+-----------+----------+
| parent_id | child_id |
+-----------+----------+
| 1 | 2 |
| 2 | 4 |
| 3 | 4 |
+-----------+----------+
If there is a Model that is not a parent or child (at some point) of another Model whose type is 5, it is not valid and hence should be deleted.
This means that Model 1, 2 should be deleted because at no point do they have a model as parent or child with type_id = 5.
There are N levels in this hierarchy, but there are no circular relationship (ie. 1 -> 2; 2 -> 1 will not exist).
Any idea on how to do this?
Comments are dispersed throughout the code.
Schema:
CREATE TABLE `Models`
( -- Note that for now the AUTO_INC is ripped out of this for ease of data insertion
-- otherwise we lose control at this point (this is just a test)
-- `model_id` MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`model_id` MEDIUMINT UNSIGNED PRIMARY KEY,
`type_id` SMALLINT UNSIGNED NOT NULL
)ENGINE = InnoDB;
CREATE TABLE `Model_Hierarchy`
( -- OP comments state these are more like components
--
-- #Drew imagine b being a product and a and c being two different ways to package it.
-- Hence b is contained in both a and c respectively and separately (ie. customer can buy
-- both a and c), however, any change (outside of the scope of this question) to b is
-- reflected to both a and c. `Model_Hierarchy can be altered, yes (the project is
-- in an early development). Max tree depth is unknown (this is for manufacturing...
-- so a component can consist of a component... that consist of further component etc.
-- no real limit). How many rows? Depends, but I don't expect it to exceed 2^32.
--
--
-- Drew's interpretation of the the above: `a` is a parent of `b`, `c` is a parent of `b`
--
`parent_id` MEDIUMINT UNSIGNED NOT NULL,
`child_id` MEDIUMINT UNSIGNED NOT NULL,
INDEX `fk_Model_Hierarchy_Models1_idx` (`parent_id` ASC),
INDEX `fk_Model_Hierarchy_Models2_idx` (`child_id` ASC),
PRIMARY KEY (`parent_id`, `child_id`),
key(`child_id`,`parent_id`), -- NoteA1 pair flipped the other way (see NoteA2 in stored proc)
CONSTRAINT `fk_Model_Hierarchy_Models1`
FOREIGN KEY (`parent_id`)
REFERENCES `Models` (`model_id`)
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT `fk_Model_Hierarchy_Models2`
FOREIGN KEY (`child_id`)
REFERENCES `Models` (`model_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
)ENGINE = InnoDB;
CREATE TABLE `GoodIds`
( -- a table to determine what not to delete from models
`id` int auto_increment primary key,
`model_id` MEDIUMINT UNSIGNED,
`has_been_processed` int not null,
dtFinished datetime null,
-- index section (none shown, developer chooses later, as he knows what is going on)
unique index(model_id), -- supports the "insert ignore" concept
-- FK's below:
foreign key `fk_abc_123` (model_id) references Models(model_id)
)ENGINE = InnoDB;
To drop and start over from the top:
-- ------------------------------------------------------------
-- reverse order is happier
drop table `GoodIds`;
drop table `Model_Hierarchy`;
drop table `Models`;
-- ------------------------------------------------------------
Load Test Data:
insert Models(model_id,type_id) values
(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,5),(10,1),(11,1),(12,1);
-- delete from Models; -- note, truncate does not work on parents of FK's
insert Model_Hierarchy(parent_id,child_id) values
(1,2),(1,3),(1,4),(1,5),
(2,1),(2,4),(2,7),
(3,2),
(4,8),(4,9),
(5,1),
(6,1),(6,2),
(7,1),(7,10),
(8,1),(8,12),
(9,11),
(10,11),
(11,12);
-- Set 2 to test (after a truncate / copy paste of this below to up above):
(1,2),(1,3),(1,4),(1,5),
(2,1),(2,4),(2,7),
(3,2),
(4,8),(4,9),
(5,1),
(6,1),(6,2),
(7,1),(7,10),
(8,1),(8,12),
(9,1),
(10,11),
(11,12);
-- truncate table Model_Hierarchy;
-- select * from Model_Hierarchy;
-- select * from Models where type_id=5;
Stored Procedure:
DROP PROCEDURE if exists loadUpGoodIds;
DELIMITER $$
CREATE PROCEDURE loadUpGoodIds()
BEGIN
DECLARE bDone BOOL DEFAULT FALSE;
DECLARE iSillyCounter int DEFAULT 0;
TRUNCATE TABLE GoodIds;
insert GoodIds(model_id,has_been_processed) select model_id,0 from Models where type_id=5;
WHILE bDone = FALSE DO
select min(model_id) into #the_Id_To_Process from GoodIds where has_been_processed=0;
IF #the_Id_To_Process is null THEN
SET bDone=TRUE;
ELSE
-- First, let's say this is the parent id.
-- Find the child id's that this is a parent of
-- and they qualify as A Good Id to save into our Good table
insert ignore GoodIds(model_id,has_been_processed,dtFinished)
select child_id,0,null
from Model_Hierarchy
where parent_id=#the_Id_To_Process;
-- Next, let's say this is the child id.
-- Find the parent id's that this is a child of
-- and they qualify as A Good Id to save into our Good table
insert ignore GoodIds(model_id,has_been_processed,dtFinished)
select child_id,0,null
from Model_Hierarchy
where child_id=#the_Id_To_Process;
-- NoteA2: see NoteA1 in schema
-- you can feel the need for the flipped pair composite key in the above
UPDATE GoodIds set has_been_processed=1,dtFinished=now() where model_id=#the_Id_To_Process;
END IF;
-- safety bailout during development:
SET iSillyCounter = iSillyCounter + 1;
IF iSillyCounter>10000 THEN
SET bDone=TRUE;
END IF;
END WHILE;
END$$
DELIMITER ;
Test:
call loadUpGoodIds();
-- select count(*) from GoodIds; -- 9 / 11 / 12
select * from GoodIds limit 10;
+----+----------+--------------------+---------------------+
| id | model_id | has_been_processed | dtFinished |
+----+----------+--------------------+---------------------+
| 1 | 9 | 1 | 2016-06-28 20:33:16 |
| 2 | 11 | 1 | 2016-06-28 20:33:16 |
| 4 | 12 | 1 | 2016-06-28 20:33:16 |
+----+----------+--------------------+---------------------+
Mop up calls, can be folded into stored proc:
-- The below is what to run
-- delete from Models where model_id not in (select null); -- this is a safe call (will never do anything)
-- the above is just a null test
delete from Models where model_id not in (select model_id from GoodIds);
-- Error 1451: Cannot delete or update a parent row: a FK constraint is unhappy
-- hey the cascades did not work, can figure that out later
-- Let go bottom up for now. Meaning, to honor FK constraints, kill bottom up.
delete from Model_Hierarchy where parent_id not in (select model_id from GoodIds);
-- 18 rows deleted
delete from Model_Hierarchy where child_id not in (select model_id from GoodIds);
-- 0 rows deleted
delete from Models where model_id not in (select model_id from GoodIds);
-- 9 rows deleted / 3 remain
select * from Models;
+----------+---------+
| model_id | type_id |
+----------+---------+
| 9 | 5 |
| 11 | 1 |
| 12 | 1 |
+----------+---------+

Query on delete cascade not success in child table

I have created two table that have a condition like this.
Parent
CREATE TABLE IF NOT EXISTS `tbl_requestfix` (
`id_request` varchar(10) NOT NULL,
`waktu_tutup_request` datetime DEFAULT NULL,
`id_complaint` varchar(10) NOT NULL,
PRIMARY KEY (`id_request`),
KEY `FK_tbl_requestfix_tbl_detail_complaint` (`id_complaint`),
CONSTRAINT `FK_tbl_requestfix_tbl_detail_complaint`
FOREIGN KEY
(`id_complaint`) REFERENCES `tbl_detail_complaint` (`id_complaint`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Child
CREATE TABLE IF NOT EXISTS `tbl_detail_complaint` (
`id_complaint` varchar(10) NOT NULL,
`complaint_2` text,
`timestamp_2` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id_complaint`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
When I am insert a row, there is no problem.
When I delete a row on parent, the row on child it still exist ?
Am I lost or wrong ?
DELETE FROM tbl_requestfix where id_request='001';
Thanks for the help. It so appreciated
You are calling this parent:
CREATE TABLE IF NOT EXISTS `tbl_requestfix` (
`id_request` varchar(10) NOT NULL,
`waktu_tutup_request` datetime DEFAULT NULL,
`id_complaint` varchar(10) NOT NULL,
PRIMARY KEY (`id_request`),
KEY `FK_tbl_requestfix_tbl_detail_complaint` (`id_complaint`),
CONSTRAINT `FK_tbl_requestfix_tbl_detail_complaint`
FOREIGN KEY
(`id_complaint`) REFERENCES `tbl_detail_complaint` (`id_complaint`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
You are calling this child:
CREATE TABLE IF NOT EXISTS `tbl_detail_complaint` (
`id_complaint` varchar(10) NOT NULL,
`complaint_2` text,
`timestamp_2` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id_complaint`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
The fact is that you should be able to create Parent prior to creating Child. Parents come before the kids. But you can't create Parent first:
ERROR 1215 (HY000): Cannot add foreign key constraint
So I think you need to rethink this one.
Here is an example:
Schema:
-- drop table parent;
create table parent
( -- assume your have only one parent, ok bad example, it's early
id int auto_increment primary key,
fullName varchar(100) not null
)ENGINE=InnoDB;
-- drop table child;
create table child
( id int auto_increment primary key,
fullName varchar(100) not null,
myParent int not null,
CONSTRAINT `mommy_daddy` FOREIGN KEY (myParent) REFERENCES parent(id)
ON DELETE CASCADE ON UPDATE CASCADE
)ENGINE=InnoDB;
Test the cascade:
insert parent(fullName) values ('Robert Smith'),('Kim Billings'); -- id's 1 and 2
insert child(fullName,myParent) values ('Little Bobby',1),('Sarah Smith',1);
insert child(fullName,myParent) values ('Scout Billings',2),('Bart Billings',2);
select * from child;
+----+----------------+----------+
| id | fullName | myParent |
+----+----------------+----------+
| 1 | Little Bobby | 1 |
| 2 | Sarah Smith | 1 |
| 3 | Scout Billings | 2 |
| 4 | Bart Billings | 2 |
+----+----------------+----------+
delete from parent where id=1; -- delete Robert Smith
select * from child;
+----+----------------+----------+
| id | fullName | myParent |
+----+----------------+----------+
| 3 | Scout Billings | 2 |
| 4 | Bart Billings | 2 |
+----+----------------+----------+
There, the delete of the parent cascaded to clobber kids too

long running query

1.Below query is taking around 49 sec to execute.
2.our target is need to get result in 1 to 2sec.
3.query having indexes and it was using
4.how to avoide this long time execution.
5.it is a simple query
6.if possible help me to rewrite the query.
query:
select cppm.* from cat_ctlg_product_product_map cppm, cat_product_product_map ppm where cppm.product_product_map_id = ppm.product_product_map_id and ppm.product_id = 2585682 and cppm.catalog_id in ( 2136359, 2136371);
Explain plan:
+----+-------------+-------+-------+------------------------------------+---------------------------+---------+-------+--------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+------------------------------------+---------------------------+---------+-------+--------+--------------------------------+
| 1 | SIMPLE | ppm | ref | PRIMARY,idx_3342,idx_5419 | idx_3342 | 4 | const | 1 | Using index |
| 1 | SIMPLE | cppm | range | idx_3472,fkey_cat_ctlg_produc_4100 | fkey_cat_ctlg_produc_4100 | 4 | NULL | 135334 | Using where; Using join buffer |
+----+-------------+-------+-------+------------------------------------+---------------------------+---------+-------+--------+--------------------------------+
2 rows in set (0.00 sec)
Table structures:
mysql> show create table cat_ctlg_product_product_map\G
*************************** 1. row ***************************
Table: cat_ctlg_product_product_map
Create Table: CREATE TABLE `cat_ctlg_product_product_map` (
`row_mod` datetime DEFAULT NULL,
`row_create` datetime DEFAULT NULL,
`product_product_map_id` int(11) NOT NULL,
`catalog_id` int(11) NOT NULL,
UNIQUE KEY `idx_3472` (`product_product_map_id`,`catalog_id`),
KEY `fkey_cat_ctlg_produc_4100` (`catalog_id`),
CONSTRAINT `fkey_cat_ctlg_produc_4100` FOREIGN KEY (`catalog_id`) REFERENCES `cat_catalogs` (`catalog_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fkey_cat_ctlg_produc_5415` FOREIGN KEY (`product_product_map_id`) REFERENCES `cat_product_product_map` (`product_product_map_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin
1 row in set (0.00 sec)
mysql> show create table cat_product_product_map\G
*************************** 1. row ***************************
Table: cat_product_product_map
Create Table: CREATE TABLE `cat_product_product_map` (
`row_mod` datetime DEFAULT NULL,
`row_create` datetime DEFAULT NULL,
`product_product_map_id` int(11) NOT NULL,
`owner_catalog_id` int(11) NOT NULL,
`parent_product_id` int(11) NOT NULL,
`product_id` int(11) NOT NULL,
`precedence` int(11) DEFAULT '100',
`is_default` int(11) DEFAULT NULL,
`product_product_type` enum('cross-sell','skuoption','up-sell','addon','works','kit','autocross') COLLATE latin1_bin DEFAULT NULL,
PRIMARY KEY (`product_product_map_id`),
KEY `idx_3342` (`product_id`,`product_product_type`),
KEY `idx_5251` (`parent_product_id`,`product_product_type`,`product_id`),
KEY `idx_5419` (`product_product_map_id`,`parent_product_id`,`product_id`),
KEY `fkey_cat_product_pro_4229` (`owner_catalog_id`),
KEY `cat_product_product_map_n1` (`parent_product_id`,`product_product_type`,`product_product_map_id`,`precedence`),
CONSTRAINT `fkey_cat_product_pro_3617` FOREIGN KEY (`product_id`) REFERENCES `cat_products` (`product_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fkey_cat_product_pro_4229` FOREIGN KEY (`owner_catalog_id`) REFERENCES `cat_catalogs` (`catalog_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fkey_cat_product_pro_4362` FOREIGN KEY (`parent_product_id`) REFERENCES `cat_products` (`product_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin
1 row in set (0.00 sec)
Use join
select cppm.* from cat_ctlg_product_product_map cppm
INNER JOIN cat_product_product_map ppm ON (cppm.product_product_map_id = ppm.product_product_map_id AND cppm.catalog_id in ( 2136359, 2136371))
WHERE ppm.product_id = 2585682;
Suggest you create the following indexes:
ALTER TABLE cat_ctlg_product_product_map
ADD INDEX (catalog_id, product_product_map_id);
ALTER TABLE cat_product_product_map
ADD INDEX (product_id, product_product_map_id);