Mysql trigger when on update reserved cloumn sub capacity if statements - mysql

I want to set check class capacity if will be full class should be
confirm. When I update reserved it give error. Please help. Thank you.
CREATE TRIGGER `control_class_capacity`
AFTER UPDATE ON `learningcenter_class`
FOR EACH ROW BEGIN
IF NEW.capacity - NEW.reserved = 0 THEN BEGIN
UPDATE learningcenter_class SET isconfirm = 1 WHERE class_id = NEW.class_id;
END; END IF;
END

Assuming your class_id is unique you could change the trigger to a before trigger and set NEW.ISCONFIRM. BTW if statements in MYSQL do not require begin and end statements.
drop table if exists t;
create table t(class_id int ,capacity int, reserved int, isconfirm int);
insert into t values (1,1,0,0) , (2,1,0,0);
drop trigger if exists `control_class_capacity`;
delimiter $$
CREATE TRIGGER `control_class_capacity`
before UPDATE ON t
FOR EACH ROW BEGIN
IF NEW.capacity - NEW.reserved = 0 THEN
SET new.isconfirm = 1;
END IF;
END $$
delimiter ;
update t set reserved = 1 where class_id = 1;
select * from t;
+----------+----------+----------+-----------+
| class_id | capacity | reserved | isconfirm |
+----------+----------+----------+-----------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 0 | 0 |
+----------+----------+----------+-----------+
2 rows in set (0.00 sec)

Related

How to make triggers for delete and adding with if statement MySQL?

have two table's Queue (appointment_id, actual_time) Queue_Summary (date, doctor_id, num_of_patients)
The first is all the queues there are and the second is how many queues for each doctor on a certain date. I need to build a trigger that updates the num_of_patients, every time in Queue that a queue is added I need to add to a doctor num_of_patients on that date. Also when removing.
I have just counted the number of queues given a doctor_id and date, made it into two triggers.
But the only problem I have is where do I place the if statement that checks if this date is on Queue_Summary and if not adds it.
(P.S - Im not 100% on thoes also as my database is a bit off and does tons of problems, if there are any problem in thoes statments I'll be more them happy to know)
delimiter //
CREATE TRIGGER update_queue_summary
AFTER DELETE ON queue
FOR EACH ROW
BEGIN
update queue_summary as qs set num_of_patient = (
select count(appointment_id)
from queue as q join appointment as a on appointment_id
where a.doctor_id=qs.doctor_id and date(qs.actual_time)=date(qs.date())
group by appointment_id
) where doctor_id=qs.doctor_id and date(qs.actual_time)=date(qs.date());
END;//
delimiter ;
delimiter //
CREATE TRIGGER update_queue_summary
AFTER insert ON queue
FOR EACH ROW
BEGIN
update queue_summary as qs set num_of_patient = (
select count(appointment_id)
from queue as q join appointment as a on appointment_id
where a.doctor_id=qs.doctor_id and date(qs.actual_time)=date(qs.date())
group by appointment_id
) where doctor_id=qs.doctor_id and date(qs.actual_time)=date(qs.date());
END;//
delimiter ;
You should carry out an existence test in your trigger. For example
drop table if exists queue,queue_summary;
create table queue (appointment_id int auto_increment primary key, doctor_id int,actual_time datetime);
create table Queue_Summary (date date, doctor_id int, num_of_patients int);
delimiter $$
create trigger ut after insert on queue
for each row
begin
if not exists (select 1 from queue_summary where date = date(new.actual_time) and doctor_id = new.doctor_id) then
insert into queue_summary values(date(new.actual_time),new.doctor_id,1);
else
update queue_summary
set num_of_patients = num_of_patients + 1
where date = date(new.actual_time) and doctor_id = new.doctor_id;
end if;
end $$
delimiter ;
insert into queue (doctor_id,actual_time) values(1,'2020-05-03 09:00'),(1,'2020-05-03 09:30');
select * from queue;
select * from queue_summary;
MariaDB [sandbox]> select * from queue;
+----------------+-----------+---------------------+
| appointment_id | doctor_id | actual_time |
+----------------+-----------+---------------------+
| 1 | 1 | 2020-05-03 09:00:00 |
| 2 | 1 | 2020-05-03 09:30:00 |
+----------------+-----------+---------------------+
2 rows in set (0.001 sec)
MariaDB [sandbox]> select * from queue_summary;
+------------+-----------+-----------------+
| date | doctor_id | num_of_patients |
+------------+-----------+-----------------+
| 2020-05-03 | 1 | 2 |
+------------+-----------+-----------------+
1 row in set (0.001 sec)
And a delete trigger is similar but simpler
delimiter $$
create trigger dt after delete on queue
for each row
begin
if exists (select 1 from queue_summary where date = date(OLD.actual_time) and doctor_id = old.doctor_id) then
update queue_summary
set num_of_patients = num_of_patients - 1
where date = date(old.actual_time) and doctor_id = old.doctor_id;
end if;
end $$
delimiter ;
The existence check is entirely cosmetic since a delete won't complain if there is nothing to delete.

MySQL : Cascade update on same table

I have a MySQL table in which each records references its parent_id :
| id | Summary | parent_id | hidden |
-------------------------------------
| 1 | First | NULL | 0 |
| 2 | Hello | 1 | 0 |
| 3 | john | 1 | 0 |
| 4 | Second | NULL | 0 |
| 5 | World | 2 | 0 |
| 6 | Doe | 4 | 0 |
I would like to cascade update so that if line 1 becomes hidden, its child (line 2) and the childs of its childs (line 5) becomes also hidden.
Is it possible with MySQL.
I already have a DELETE ON CASCADE constraint which works fine.
CONSTRAINT FK_ID_With_CascadeDelete FOREIGN KEY (parent_id) REFERENCES MyTable (id) ON DELETE CASCADE
You can use Stored Procedure as follows.
DELIMITER $$
DROP PROCEDURE IF EXISTS `update_node`$$
CREATE PROCEDURE `update_node`(IN p_id INT)
proc: BEGIN
DECLARE e_no_id CONDITION FOR SQLSTATE '45000';
IF ( p_id IS NULL ) THEN
SIGNAL e_no_id SET MESSAGE_TEXT = 'The id cannot be empty.';
LEAVE proc;
END IF;
DROP TEMPORARY TABLE IF EXISTS del_temp_table;
CREATE TEMPORARY TABLE IF NOT EXISTS del_temp_table(
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
delids INTEGER UNSIGNED NOT NULL,
node INTEGER DEFAULT 0
);
SET #rept := #loopcount := 1;
INSERT INTO del_temp_table (delids, node) SELECT p_id, #rept;
myloop: WHILE (1 = 1)
DO
SELECT COUNT(id) AS cnt FROM test WHERE `parent_id` IN ( SELECT DISTINCT(delids) FROM del_temp_table WHERE node = #rept ) INTO #loopcount;
IF (#loopcount = 0) THEN
LEAVE myloop;
ELSE
SET #rept := #rept + 1;
SELECT GROUP_CONCAT(d1.delids) INTO #wherein FROM ( SELECT DISTINCT(delids) FROM del_temp_table WHERE node = (#rept - 1) ) AS d1;
INSERT INTO del_temp_table (delids, node) SELECT id, #rept FROM test WHERE FIND_IN_SET( parent_id, #wherein ) > 0;
END IF ;
END WHILE myloop;
UPDATE test SET hidden = 1 WHERE id IN ( SELECT delids FROM del_temp_table );
END$$
DELIMITER ;
Here i used Temporary table to store recursive nodes and iterated each time by using that table to fetch next child and inserted it into same table.
I believe this could help you. Replace table name test with your table name
I think you simply can't do that. Even with an UPDATE TRIGGER you cannot update other rows on the same table.
Maybe this is not the answer you were expecting but probably your best choice is to use a PROCEDURE like this:
DELIMITER //
CREATE PROCEDURE UpdateHiden(IN pid INT, IN phidden INT)
BEGIN
UPDATE mytable
SET HIDDEN = phidden
WHERE ID = pid OR parent_id = pid;
END; //
DELIMITER ;
See sample on DB Fiddle here

Trigger "AFTER INSERT" doesn't work, after insertion if I Add values in tables?

Purpose of trigger:
I should +add some number 50 to that user to table money where in table paym both columns table1 and table2 are not empty.
For example: User 'John' has both columns not empty and to him added 50 in table money.
Example in table below:
table: paym
ID username table1 Table2
+-------+-------------+-------------+-----------+
| 1 | John | Value | Value |
+-------+-------------+-------------+-----------+
| 2 | Alex | Null | Null |
+-------+-------------+-------------+-----------+
Table: money
ID username total_money
+-------+-------------+-------------+
| 1 | John | 50 |
+-------+-------------+-------------+
| 2 | Alex | 0 |
+-------+-------------+-------------+
Trigger below, works perfectly only when we insert all tables at one time. But it doesn't work if you insert only username two tables empty and after insertion, if you add values to empty tables table1 and table2 triggers not works at this point! Can we solve this problem???
Trigger should work even if we add value to the table After insertion!
DELIMITER $$
CREATE trigger update_money_after_paym
AFTER INSERT ON paym
FOR EACH ROW
BEGIN
IF (NEW.table1 IS NOT NULL AND NEW.table2 IS NOT NULL) THEN
UPDATE money SET total_money = total_money + 50 WHERE username = NEW.username;
END IF;
END;
$$
DELIMITER;
Not that trigger. It is an insert trigger, so it doesn't get called for an update.
If you want an update trigger, then define one:
DELIMITER $$
CREATE trigger update_money_after_paym
AFTER UPDATE ON paym
FOR EACH ROW
BEGIN
IF (NEW.table1 IS NOT NULL AND NEW.table2 IS NOT NULL) THEN
UPDATE money m
SET total_money = total_money + 50
WHERE m.username = NEW.username;
END IF;
END;
$$
DELIMITER;
This may not do exactly what you want. For instance, you might only want to add 50 when the previous values are both NULL:
DELIMITER $$
CREATE trigger update_money_after_paym
AFTER UPDATE ON paym
FOR EACH ROW
BEGIN
IF (NEW.table1 IS NOT NULL AND NEW.table2 IS NOT NULL AND
OLD.table1 IS NULL AND old.table2 IS NULL) THEN
UPDATE money m
SET total_money = total_money + 50
WHERE m.username = NEW.username;
END IF;
END;
$$
DELIMITER;

mysql stored procedure issue: insert runs first and always whatever If condition I put

Need quick help, in below SQL insert is fired first then other select queries are fired. insert statement is executed whatever If condition I put.
I am testing this in phpMyAdmin.
I tried to also convert the insert statement in to separate stored procedure but then also result is same.
Thanks in Advance..
DELIMITER $$
DROP PROCEDURE IF EXISTS get_top$$
CREATE PROCEDURE get_top(
IN tolerance INT,
IN cred INT,
IN cgreen INT,
IN cblue INT,
IN userID INT,
IN mapID BIGINT
)
BEGIN
DECLARE topList VARCHAR(255) DEFAULT NULL;
DECLARE top1 VARCHAR(255) DEFAULT NULL;
DECLARE top2 VARCHAR(255) DEFAULT NULL;
DECLARE top3 VARCHAR(255) DEFAULT NULL;
DECLARE get_result VARCHAR(255) DEFAULT NULL;
DECLARE dev_notes VARCHAR(255) DEFAULT NULL;
SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
SELECT CONCAT(top_1, ';', top_2, ';', top_3) INTO topList
FROM Tops
WHERE red = cred AND green = cgreen AND blue = cblue
ORDER BY top_ID asc
LIMIT 0 , 1 ;
SELECT topList,cred,cgreen,cblue;
IF topList IS NULL THEN BEGIN
SELECT top_1, top_2, top_3
INTO top1, top2, top3
FROM Tops
WHERE top_1>0
LIMIT 0 , 1 ;
SELECT "in IF",top1,CHAR_LENGTH(top1);
IF (top1 IS NULL) THEN
SET get_result:= 'None';
ELSE
SET get_result:= 'Nearest';
END IF;
SET topList=top1+ ','+ top2+ ','+ top3;
SET dev_notes='result:'+get_result+' mapID:'+mapID+' User ID:'+userID+' date/time:'+NOW();
SELECT topList,get_result;
INSERT INTO Tops (red,green,blue,top_1,top_2,top_3,notes) VALUES (cred,cgreen,cblue,top1,top2,top3,dev_notes);
END;
ELSE BEGIN
SET get_result:= 'Exact';
SELECT "in else",topList,get_result,dev_notes;
END; END IF;
IF CHAR_LENGTH(mapID)>0 THEN
UPDATE Map SET toponym=toponymList, toponym_conf=get_result WHERE map_ID=mapID;
END IF;
END$$
DELIMITER ;
I have amended you code to write debug messages to a table so that I can illustrate what is happening.
DELIMITER $$
DROP PROCEDURE IF EXISTS get_top$$
CREATE PROCEDURE get_top(
IN tolerance INT,
IN cred INT,
IN cgreen INT,
IN cblue INT,
IN userID INT,
IN mapID BIGINT
)
BEGIN
DECLARE topList VARCHAR(255) DEFAULT NULL;
declare topsid int;
DECLARE top1 VARCHAR(255) DEFAULT null;
DECLARE top2 VARCHAR(255) DEFAULT null;
DECLARE top3 VARCHAR(255) DEFAULT null;
DECLARE get_result VARCHAR(255) DEFAULT NULL;
DECLARE dev_notes VARCHAR(255) DEFAULT NULL;
SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
SELECT top_id,CONCAT(top_1, ';', top_2, ';', top_3) INTO topsid,topList
FROM Tops
WHERE red = cred AND green = cgreen AND blue = cblue
ORDER BY top_ID asc
LIMIT 0 , 1 ;
insert into debug_table (msg) values (concat('Start topsid:', coalesce(topsid,'not found'),' toplist:',coalesce(topList,'null'),' cred:',cred,' cgreen:',cgreen,' cblue:',cblue));
IF topList IS NULL THEN
BEGIN
SELECT top_1, top_2, top_3
INTO top1, top2, top3
FROM Tops
WHERE top_1>0
LIMIT 0 , 1 ;
insert into debug_table (msg) values (concat("in IF",' top1:',coalesce(top1,'null'),' len top1:',if(top1 is not null,CHAR_LENGTH(top1),0)));
IF (top1 IS NULL) THEN
SET get_result:= 'None';
ELSE
SET get_result:= 'Nearest';
END IF;
SET topList=top1+ ','+ top2+ ','+ top3;
#SET dev_notes='result:'+get_result+' mapID:'+mapID+' User ID:'+userID+' date/time:'+NOW();
SET dev_notes=CONCAT('result:',get_result,' mapID:',mapID,' User ID:',userID,' date/time:',NOW());
insert into debug_table (msg) values (concat('about to insert toplist:',coalesce(topList,'null'),' get_result:',get_result,' dev_notes:',DEV_NOTES));
INSERT INTO Tops (red,green,blue,top_1,top_2,top_3,notes) VALUES (cred,cgreen,cblue,top1,top2,top3,dev_notes);
END;
ELSE BEGIN
SET get_result:= 'Exact';
insert into debug_table (msg) values (concat(' in else toplist:',coalesce(topList,'null'),' get_result:',get_result,' dev_notes:',DEV_NOTES));
END;
END IF;
#SELECT CHAR_LENGTH(MAPID);
#IF CHAR_LENGTH(mapID)>0 THEN
# UPDATE Map SET toponym=toponymList, toponym_conf=get_result WHERE map_ID=mapID;
#END IF;
END$$
DELIMITER ;
So if tops looks something like this
DROP TABLE IF EXISTS TOPS;
CREATE TABLE TOPS(TOP_ID INT AUTO_INCREMENT PRIMARY KEY,
red INT,green INT,blue INT,top_1 varchar(4),top_2 varchar(4),top_3 varchar(4),notes VARCHAR(100));
And I do this
ariaDB [sandbox]> TRUNCATE TABLE TOPS;
Query OK, 0 rows affected (0.16 sec)
MariaDB [sandbox]> truncate table debug_table;
Query OK, 0 rows affected (0.24 sec)
MariaDB [sandbox]> CALL GET_TOP(1,1,1,1,'1','1');
Query OK, 1 row affected (0.17 sec)
MariaDB [sandbox]> select * from tops;
+--------+------+-------+------+-------+-------+-------+-------------------------------------------------------------+
| TOP_ID | red | green | blue | top_1 | top_2 | top_3 | notes |
+--------+------+-------+------+-------+-------+-------+-------------------------------------------------------------+
| 1 | 1 | 1 | 1 | NULL | NULL | NULL | result:None mapID:1 User ID:1 date/time:2017-07-20 09:45:00 |
+--------+------+-------+------+-------+-------+-------+-------------------------------------------------------------+
1 row in set (0.00 sec)
MariaDB [sandbox]> CALL GET_TOP(1,1,1,1,'1','1');
Query OK, 1 row affected (0.10 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> SELECT * FROM debug_table;
+----+--------------------------------------------------------------------------------------------------------------------+
| id | msg |
+----+--------------------------------------------------------------------------------------------------------------------+
| 1 | Start topsid:not found toplist:null cred:1 cgreen:1 cblue:1 |
| 2 | in IF top1:null len top1:0 |
| 3 | about to insert toplist:null get_result:None dev_notes:result:None mapID:1 User ID:1 date/time:2017-07-20 09:45:00 |
| 4 | Start topsid:1 toplist:null cred:1 cgreen:1 cblue:1 |
| 5 | in IF top1:null len top1:0 |
| 6 | about to insert toplist:null get_result:None dev_notes:result:None mapID:1 User ID:1 date/time:2017-07-20 09:45:00 |
+----+--------------------------------------------------------------------------------------------------------------------+
6 rows in set (0.00 sec)
I would expect on the first call that no record will be found in tops and topslist will be null and this is proved by the first three records in the debug_table. On the second call a record is found in tops but since top_1,top_2 and top_3 are null then topslist is again null. The select in the if "fails" because there are no tops_1 records with a value > 0 so another record is inserted with null values to tops this is traceable in the debug_table records 4 -6. BTW checking a varchar field for a value > 0 is not a good idea.

Duplicate a record with some changes in stored proc mysql

my table is:
+------+---------+----------+--------+---------+------------+----------+----------------+------------------+-----------+--------+--------+---------+-------+
| r_id | r_width | r_height | r_code | r_store | r_provider | r_parent | r_regiter_time | r_last_used_time | r_comment | r_type | r_open | r_usage | r_log |
+------+---------+----------+--------+---------+------------+----------+----------------+------------------+-----------+--------+--------+---------+-------+
| 1 | 2000 | 3500 | test 1 | 0 | 0 | 0 | 0 | 0 | nop | NULL | NULL | 99.3618 | NULL |
| 2 | 2000 | 3000 | usd22 | 2 | 1 | 0 | 1440915529 | 1440915529 | comment | 2 | 0 | 13.0833 | NULL |
| 3 | 3000 | 2500 | qb88 | 1 | 2 | 0 | 1440921466 | 1440921466 | commex | 3 | 0 | 0 | NULL |
+------+---------+----------+--------+---------+------------+----------+----------------+------------------+-----------+--------+--------+---------+-------+
3 rows in set (0.00 sec)
AND this my stored procedure :
CREATE DEFINER=`root`#`localhost` PROCEDURE `ROLE_SPLIT_V`(IN `id` INT, IN `top` INT)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE exit handler for sqlexception
BEGIN
SHOW ERRORS LIMIT 1 ;
ROLLBACK;
END;
DECLARE exit handler for sqlwarning
BEGIN
SHOW WARNINGS LIMIT 1;
ROLLBACK;
END;
START TRANSACTION;
SET #MyRec = (SELECT `r_width`,(`r_height` - top ) as 'r_height' ,CONCAT(`r_code`,'_',ROUND(RAND() * 1000)) as 'r_code' ,`r_store`,`r_provider`,
`r_parent`,`r_regiter_time`,`r_last_used_time`,`r_comment`,`r_type`,`r_open`,`r_usage`,`r_log` FROM prfix_role WHERE r_id = id) ;
-- UPDATE prfix_role SET prfix_role.r_height = top WHERE prfix_role.r_id = id ;
INSERT INTO prfix_role (`r_width`,`r_height`,`r_code`,`r_store`,`r_provider`,`r_parent`,`r_regiter_time`,`r_last_used_time`,`r_comment`,`r_type`,`r_open`,`r_usage`,`r_log`)
VALUES (MyRec);
SET #lst_id = LAST_INSERT_ID();
-- UPDATE prfix_slice SET s_top = s_top - top,s_role_id = lst_id WHERE s_role_id = id AND s_top > top ;
COMMIT;
END
But not see any change after run in my db I have this error:
Operand should contain 1 column(s)
You are not using session variable properly.
Instead, in your case of requirement, I suggest you to go with local variables to read-into values from table. And use them with insert statement.
Example:
START TRANSACTION;
BEGIN
DECLARE _r_width INT; -- or whatever it be
DECLARE _r_height INT; -- or whatever it be
DECLARE _r_code VARCHAR(255);
DECLARE _r_store INT; -- or whatever it be
DECLARE _r_provider INT; -- or whatever it be
DECLARE _r_width INT; -- or whatever it be
--- all other required fields here
-- now select values into above variables
SELECT `r_width`, (`r_height` - top ) as 'r_height'
, CONCAT(`r_code`,'_',ROUND(RAND() * 1000)) as 'r_code'
, `r_store`,`r_provider`
, `r_parent`, `r_regiter_time`, `r_last_used_time`
, `r_comment`, `r_type`, `r_open`
, `r_usage`, `r_log`
INTO _r_width, _r_height, _r_code, _r_store
-- rest of other field variables should go here
FROM prfix_role WHERE r_id = id ;
-- now use the variable values with insert statement
INSERT INTO prfix_role ( `r_width`, `r_height`, `r_code`, `r_store`
, `r_provider`, `r_parent`, `r_regiter_time`, `r_last_used_time`
, `r_comment`, `r_type`, `r_open`, `r_usage`, `r_log` )
VALUES ( _r_width, r_height, _r_code, _r_store, .... );
-- if you want to use last inserted value,
-- you can directly call it in the statement
UPDATE prfix_slice
SET s_top = s_top - top
, s_role_id = LAST_INSERT_ID()
WHERE s_role_id = id
AND s_top > top ;
END; -- end transaction
I changing my code to this and solve problem:
CREATE DEFINER=`root`#`localhost` PROCEDURE `ROLE_SPLIT_V`(IN `id` INT, IN `top` INT)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE exit handler for sqlexception
BEGIN
SHOW ERRORS LIMIT 1 ;
ROLLBACK;
END;
DECLARE exit handler for sqlwarning
BEGIN
SHOW WARNINGS LIMIT 1;
ROLLBACK;
END;
START TRANSACTION;
-- SET #MyRec = ;
--
INSERT INTO prfix_role SELECT NULL,`r_width`,(`r_height` - top ) as 'r_height' ,CONCAT(`r_code`,'_',ROUND(RAND() * 1000)) as 'r_code' ,`r_store`,`r_provider`,
`r_parent`,`r_regiter_time`,`r_last_used_time`,`r_comment`,`r_type`,`r_open`,`r_usage`,`r_log` FROM prfix_role WHERE r_id = id ;
UPDATE prfix_role SET prfix_role.r_height = top WHERE prfix_role.r_id = id ;
SET #lst_id = LAST_INSERT_ID();
UPDATE prfix_role SET prfix_role.r_height = top WHERE prfix_role.r_id = id ;
UPDATE prfix_slice SET s_top = s_top - top,s_role_id = #lst_id WHERE s_role_id = id AND s_top > top ;
COMMIT;
END