Trigger to validate room capacity - mysql

I'm trying to do a room capacity validation for a specific date using a before trigger.
This is the current trigger I'm using:
delimiter $$
create trigger my_insert_trigger before insert on my_table
for each row
begin
if (select count(*) from my_table where room_type = new.room_type) > 3 then
signal sqlstate '45000';
end if;
end;
$$
delimiter ;
I currently have two columns in the same table which are date and room, this is my desired output
However this would not be the case because the trigger will still limit 'Single' three times regardless of date.

do a room capacity validation for a specific date
Just add the date to the control query:
delimiter $$
create trigger my_insert_trigger before insert on my_table
for each row
begin
if (
select count(*)
from my_table t
where t.room_type = new.room_type and t.date = new.date
) >= 3 then
signal sqlstate '45000';
end if;
end;
$$
delimiter ;
Note: because it has condition > 3, your existing code would allow 4 records per room. I changed that to >= 3 so only 3 records are allowed per room and date, which seems to be what you are looking for.

Related

'Select' and 'insert into' multiple rows by a My Sql event

I need to write a MySql Event to select some values from a table under some conditions and put those values in a second table. By the select statement. I get multiple rows, so I need to store data in the second table as a batch. How can I achieve this? I wrote an event to select one row. But what I need to do is select multiple rows and store as a batch.
The event I wrote is as below.
DELIMITER $$
CREATE EVENT salary_add
ON SCHEDULE EVERY 24 HOUR
DO
BEGIN
DECLARE month_end DATETIME;
DECLARE today DATETIME;
DECLARE reg_id VARCHAR(6);
DECLARE sal INT(8);
SET month_end = LAST_DAY(DATE(NOW()));
SET today = DATE(NOW());
IF month_end=today THEN
SELECT register_id,salary INTO reg_id,sal FROM employees
WHERE status ='1' LIMIT 1;
INSERT INTO tbl_salary (register_id,amount,salary_date,status) VALUES (reg_id,sal,today,'0');
END IF;
END $$
DELIMITER ;
You can insert selected rows into the target table at once. For example:
DELIMITER $$
CREATE EVENT salary_add
ON SCHEDULE EVERY 24 HOUR
DO
BEGIN
DECLARE month_end DATETIME;
SET month_end = LAST_DAY(CURDATE());
IF month_end=CURDATE() THEN
INSERT INTO tbl_salary (register_id, amount, salary_date, status)
SELECT register_id,
salary,
CURDATE(),
'0'
FROM employees
WHERE status ='1'
END IF;
END $$
DELIMITER ;

MySQL trigger to multiply value

I am trying to create a trigger that will multiply the sales_price field by -1, the sales table is like this transaction type, it has varchar R for refund and S for Sales.
This is the trigger I am trying to create:
delimiter $$
CREATE trigger refund_negative before insert on sale
for each row
begin
set new.SALE_PRICE = new.SALE_PRICE *(-1)
where TRA_TYPE = 'R';
end;
delimiter $$
Try this one:
CREATE TRIGGER `refund_negative` BEFORE INSERT ON `sales` FOR EACH ROW BEGIN
IF NEW.TRA_TYPE='R' THEN
SET NEW.price = NEW.price * -1;
END IF;
END
so basically it just test whether TRA_TYPE is equal to 'R' and if so, NEW.price is multiplied by negative one.

Avoid firing trigger by another trigger in MYSQL

my problem is as follows:
Table A contains list of "Tasks"
Table B contains "TaskProgress" - just an information about time spent on task, user ID, task ID and note
On table A (Tasks), I have trigger, which updates datetime of last change - column DateChanged (intended to capture datetime of edits made by user)
On table B (TaskProgress) I have trigger, which updates total time spent on a task (sum all times for given Task_ID and update column TotalTime in table A)
I wish to update DateChanged in Table A only when user mades the update (which is every time except when trigger on table B updates TotalTime)
So I wonder, whether there is a way how to tell the database not to fire TRIGGER when updating the values in another trigger.
/* set date of last change and date od closing of task */
DELIMITER $$
CREATE TRIGGER before_tasks_update
BEFORE UPDATE ON tasks
FOR EACH ROW BEGIN
SET new.DateChanged = NOW();
IF new.Status_ID = 3 THEN
SET new.DateClosed = NOW();
END IF;
END$$
DELIMITER ;
/* set total time spent on task */
DELIMITER $$
CREATE TRIGGER after_taskprogress_insert
AFTER INSERT ON taskprogress
FOR EACH ROW BEGIN
DECLARE sumtime TIME;
SET #sumtime := (SELECT SEC_TO_TIME( SUM( TIME_TO_SEC( `timeSpent` ) ) )
FROM taskprogress WHERE Task_ID = new.Task_ID);
UPDATE `tasks` SET TimeReal = #sumtime WHERE ID = new.Task_ID;
END $$
DELIMITER ;
I use MySQL 5.5.40
Thanks, zbynek
Add a check to verify that the update implies a new TimeReal value,since only the second trigger updates that column.
DELIMITER $$
CREATE TRIGGER before_tasks_update
BEFORE UPDATE ON tasks
FOR EACH ROW BEGIN
IF new.TimeReal=old.TimeReal THEN SET new.DateChanged = NOW();
END IF;
IF new.TimeReal=old.TimeReal AND new.Status_ID = 3 THEN
SET new.DateClosed = NOW();
END IF;
END$$
DELIMITER ;

INSERT INTO if conditions are met

A user is only meant to have up to 3 keys registered to his account at any one time. To add a new key, the user must first delete another key to "make room" for a new one.
I want this to be checked server-side, but I can't get the query to work. Here is what I tried:
IF (SELECT COUNT(serial_key_nbr)
FROM keys_table WHERE user_id = 9) <= 2
THEN INSERT INTO keys_table (user_id, serial_key_nbr)
VALUES (9, 'abc123')
How to do this?
You can use the below mention Script for the same:
INSERT INTO keys_table (user_id, serial_key_nbr)
SELECT 9, 'abc123' FROM DUAL
WHERE
(SELECT COUNT(serial_key_nbr)
FROM keys_table WHERE user_id = 9)<=2
if you want to use an if to do a conditional select then I would put it in a variable like so.
BEGIN
DECLARE var1 INT;
SELECT COUNT(serial_key_nbr) INTO var1
FROM keys_table
WHERE user_id = 9;
IF var1 <= 2
THEN
INSERT INTO keys_table (user_id, serial_key_nbr)
VALUES (9, 'abc123')
END IF;
A trigger might be the way to go. If a condition is met, a trigger before inserting in the table can perform an invalid operation and cause the insert operation to fail:
delimiter $$
create trigger keep_three before insert on keys_table for each row
begin
if (select count(serial_key_nbr) from keys_table where user_id = new.user_id) >= 3 then
insert into non_existent_table (non_existent_field) values (new.user_id);
end if;
end$$
delimiter ;
Ugly, but it might work.
Reference:
"MySQL Triggers: How do you abort an INSERT, UPDATE or DELETE with a trigger?"
Another solution (better I think) is to forcibly delete an entry before attepting the insert. When there are less than 3 entries, the insert procedes normally:
delimiter $$
create trigger keep_three before insert on keys_table for each row
begin
while (select count(serial_key_nbr) from keys_table where user_id = new.user_id) >= 3 do
delete from keys_table where user_id = new.user_id
-- OPTIONAL: Add an ordering criteria to define which entry is deleted first
limit 1;
end while;
end$$
delimiter ;
I think this is cleaner.
A third way (I've found it here). It will return an error message (by signaling sqlstate 45000: Unhandled user defined exception) associated with the defined condition:
delimiter $$
create trigger keep_three before insert on keys table for each row
begin
declare msg varchar(255);
declare n int default 0;
set n = (select count(serial_key_nbr) from keys_table where user_id = new.user_id);
if n >= 3 then
set msg = "INSERT failed: There must be only three entries for each user. Delete an entry first";
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
end if;
end$$
delimiter ;
A cleaner version of my first option.

MYSQL an after insert trigger to change a fields value

I have two tables stock and order and i am trying to get the trigger to work so that after the an order has been put in the order quantity is then taken away from the stock quantity field.
DELIMITER $$
CREATE TRIGGER stock_update
AFTER INSERT ON order
FOR EACH ROW
BEGIN
SET #quantity = NEW.quantity
UPDATE stock s;
SET s.quantity = OLD.quantity - NEW.quantity
FROM stock s, order o
WHERE s.ID_stock = o.ID_stock;
END;
$$
DELIMITER;
but i am just getting the error number 1064
There are several issues:
order is a reserved word, therefore you need to use back ticks around it
you don't need to use a variable #quantity
update statement was wrong
DELIMITER and ; should be separated with a space
Try this
DELIMITER $$
CREATE TRIGGER stock_update
AFTER INSERT ON `order`
FOR EACH ROW
BEGIN
UPDATE stock s
SET s.quantity = s.quantity - NEW.quantity
WHERE s.ID_stock = NEW.ID_stock;
END $$
DELIMITER ;
I'm not quite sure it will work, since I would need the table definitions in order to test it.
In each case you should remove the FROM clause and also the last line DELIMITER;. You
should also end the line SET #quantity = NEW.quantity whith a semicolon.
DELIMITER $$
CREATE TRIGGER stock_update
AFTER INSERT ON order FOR EACH ROW
BEGIN
UPDATE stock s;
SET s.quantity = OLD.quantity - NEW.quantity
WHERE s.ID_stock = NEW.ID_stock;
END;
$$