I have a MYSQL table and two of the fields are called Rate_per_unit and Cost. First I want the field Rate_per_unit to populate itself from another table called SHD_TEACHER then I want the field COST to populate itself also from RATE in SHD_TEACHER and multiplies by UNITS.
I have the following code which is giving me an error:
CREATE TRIGGER RATE_PER_UNIT_1
BEFORE INSERT ON SHD_SCHEDULE
FOR EACH ROW
SET NEW.RATE_PER_UNIT =
(
SELECT RATE
FROM SHD_TEACHER
WHERE TEACHERID = NEW.TEACHER_ID
LIMIT 1
)
SET NEW.COST = (
SELECT RATE
FROM SHD_TEACHER
WHERE TEACHERID = NEW.TEACHER_ID
) * UNITS
Any help please?
thanks
using your syntax, I would expect a delimiter statement and a begin/end block. So, try this:
DELIMITER $$
CREATE TRIGGER RATE_PER_UNIT_1
BEFORE INSERT ON SHD_SCHEDULE
FOR EACH ROW
BEGIN
SET NEW.RATE_PER_UNIT =
(
SELECT RATE
FROM SHD_TEACHER t
WHERE t.TEACHERID = NEW.TEACHER_ID
LIMIT 1
)
SET NEW.COST = (
SELECT t.RATE
FROM SHD_TEACHER t
WHERE t.TEACHERID = NEW.TEACHER_ID
) * NEW.UNITS
END $$
DELIMITER ;
You have a limit 1 in the first subquery, suggesting that there might be multiple matches. If so, you will get a run-time error in the second. Also, UNITS is just hanging out there, all alone. I assumed it is in the NEW record.
Here is another way to write this:
DELIMITER $$
CREATE TRIGGER RATE_PER_UNIT_1
BEFORE INSERT ON SHD_SCHEDULE
FOR EACH ROW
BEGIN
SELECT NEW.RATE_PER_UNIT := t.RATE, NEW.COST := t.RATE * NEW.UNITS
FROM (SELECT t.*
FROM SHD_TEACHER t
WHERE t.TEACHERID = NEW.TEACHER_ID
LIMIT 1
) t
END $$
DELIMITER ;
Related
This is my first trigger in MySql and I am having a few problems. I tried both of these pieces of code but both would not compile. I got it to work without the where clause.
CREATE TRIGGER ins_meal_details
AFTER INSERT ON meal_details
FOR EACH ROW
INSERT INTO sql_changes
SET
sc_table='book_room',
sc_reason='DINNER1',
sc_key='bh_no=NEW.bh_no,date=NEW.md_date',
sc_value='1',
sc_done =0
WHERE not exists (select 1 from booking where bh_no = NEW.bh_no and bo_date = NEW.md_date and bo_meals < 1)
CREATE TRIGGER ins_meal_details AFTER INSERT meal_details FOR EACH ROW
BEGIN
IF NOT EXISTS (select 1 from booking where bh_no = NEW.bh_no and bo_date = NEW.md_date and bo_meals < 1) THEN
INSERT INTO sql_changes (sc_table, sc_reason, sc_key, sc_value, sc_done )
VALUES ('book_room','DINNER1', 'bh_no=NEW.bh_no,date=NEW.md_date','1', 0);
END IF
END
CREATE TRIGGER ins_meal_details
AFTER INSERT
ON meal_details
FOR EACH ROW
INSERT INTO sql_changes (sc_table,
sc_reason,
sc_key,
sc_value,
sc_done)
SELECT 'book_room',
'DINNER1',
CONCAT('bh_no=',NEW.bh_no,',date=',NEW.md_date),
1,
0
WHERE NOT EXISTS (SELECT 1
FROM booking
WHERE bh_no = NEW.bh_no
AND bo_date = NEW.md_date
AND bo_meals < 1);
MySql did not like the select/where exists in my code when there is no table specified. This was due to using version 5.6 of MySql server.
This will not work: select 'works' where exists (select 1 from my-table)
The fix would be thanks to #akina to add from DUAL. The best solution.
I got round it by using a count(*) instead :-
DROP TRIGGER IF EXISTS ins_meal_details;
DELIMITER //
CREATE TRIGGER ins_meal_details
AFTER INSERT ON meal_details FOR EACH ROW
BEGIN
IF (select count(*) from booking where bh_no = NEW.bh_no and bo_date = NEW.md_date and bo_meals < 1) > 0 THEN
INSERT INTO sql_changes (sc_table,
sc_reason,
sc_key,
sc_value,
sc_done)
VALUES ('book_room','DINNER1', CONCAT('bh_no=',NEW.bh_no,',date=',NEW.md_date),'New Value', 0);
END IF;
END//
DELIMITER ;
I am creating a trigger that have a MYSQL query having IN clause look like below.
drop trigger onPublish;
delimiter $$
create trigger onPublish AFTER insert on publish_drawing_details
for each row
begin
Declare userIds VARCHAR(255);
set userIds = (select GROUP_CONCAT(refUser) from manpower where refProject=new.refProjectId and refRoleType in (select role from hr_user));
insert into notification_container(loginUserId,mailSubject,projectId,userIds,attachmentIds,ccMails,mailText,metaNotificationEventId)
values (new.submittedBy,new.mailSubject,new.refProjectId,userIds,new.attachmentIds,new.ccEmails,new.mailText,1);
end $$
It works fine if I write this like set userIds = (select GROUP_CONCAT(refUser) from manpower where refProject=new.refProjectId and refRoleType in (1,2,3,4,5));
I try it like set userIds = (select GROUP_CONCAT(refUser) from manpower where refProject=new.refProjectId and refRoleType in (select GROUP_CONCAT(role) from hr_user));
but don't work at all.
You don't need GROUP_CONCAT in inner query, try the following:
SET userIds = (
SELECT GROUP_CONCAT(refUser)
FROM manpower
WHERE refProject=new.refProjectId
AND refRoleType IN (
SELECT role
FROM hr_user
)
);
I have a table that holds a bunch of values for an order, I can do basic calculations on it until I get to a percentage. Right now I have my query as follows
declare #MyNumber decimal
set #MyNumber = (select SalesTax from [OrderHeader] where OrderHeaderID = 20)
select
sum(o.MaterialPrice) as "MatPrice",
sum(o.LaborPrice) as "LaborPrice",
sum(o.MaterialCost) as "MaterialCost",
sum(isnull(o.MaterialPrice,0)) - sum(isnull(o.MaterialCost,0)) - sum(isnull(o.LaborPrice,0)) * #MyNumber as "RESULT"
from [OrderDetail] o
inner join [OrderHeader] oh on oh.OrderHeaderID = o.OrderHeaderID
where o.OrderHeaderID = 20
PLEASE CHANGE AT LEAST NAZOV
DELIMITER $$
CREATE TRIGGER `nazov` BEFORE UPDATE
ON test
FOR EACH ROW BEGIN
SET NEW.OLD_TEXT=OLD.TEXT;
END $$
DELIMITER;
I WANT TO DO SOMETHING LIKE THIS:
CREATE TRIGGER addwinner AFTER INSERT ON bids
FOR EACH ROW BEGIN
IF exists(select * from wins as LT where LT.item_index=NEW.item_index) THEN
SELECT item_index, MIN( bid_amount )
FROM update_winnerslist AS a1
WHERE a1.item_index = NEW.item_index;
UPDATE wins SET email_id=NEW.emai_id, bid_amount=a1.bid_amount where wins.item_index=a1.item_index;
END IF;
END;
Basically what i want is to update a table using another table's tuple by comparing certain attributes.
As explained in the manual, when defining procedures/triggers/etc. that use ; within their body to separate commands, you need to define an alternate delimiter in order that the CREATE command is interpreted as a single statement.
To UPDATE with the results of the SELECT, like you describe, you can do any of:
Save the result of the SELECT in a variable which you then use in the UPDATE:
DELIMITER ;; -- or anything else you like
CREATE TRIGGER addwinner AFTER INSERT ON bids FOR EACH ROW
IF EXISTS (SELECT * FROM wins AS LT WHERE LT.item_index=NEW.item_index)
THEN
SELECT MIN(bid_amount) INTO #bid_amount
FROM update_winnerslist AS a1
WHERE a1.item_index = NEW.item_index;
UPDATE wins
SET email_id=NEW.emai_id, bid_amount=#bid_amount
WHERE wins.item_index=a1.item_index;
END IF;; -- whatever command delimiter you chose above goes here
DELIMITER ; -- reset to normal
Just use a subquery (so long as it doesn't reference the table you're updating):
DELIMITER ;; -- or anything else you like
CREATE TRIGGER addwinner AFTER INSERT ON bids FOR EACH ROW
IF EXISTS (SELECT * FROM wins AS LT WHERE LT.item_index=NEW.item_index)
THEN
UPDATE wins
SET wins.email_id=NEW.emai_id, wins.bid_amount=(
SELECT MIN(bid_amount)
FROM update_winnerslist AS a1
WHERE a1.item_index = NEW.item_index
)
WHERE item_index = NEW.item_index
END IF;; -- whatever command delimiter you chose above goes here
DELIMITER ; -- reset to normal
Or just join the tables:
DELIMITER ;; -- or anything else you like
CREATE TRIGGER addwinner AFTER INSERT ON bids FOR EACH ROW
IF EXISTS (SELECT * FROM wins AS LT WHERE LT.item_index=NEW.item_index)
THEN
UPDATE wins JOIN update_winnerslist AS a1 USING (item_index)
SET wins.email_id=NEW.emai_id, wins.bid_amount=MIN(a1.bid_amount);
WHERE item_index = NEW.item_index
END IF;; -- whatever command delimiter you chose above goes here
DELIMITER ; -- reset to normal
I've read that this can be done without issue using MyISAM as it is the default behavior , but I'm using InnoDB so need a trigger for such.
The two PK fields are batch and lineItem. If a record is deleted I want the numbering to start from the largest integer for batch. Not fill in the holes.
This is to set up a testing environment for a legacy system. So the schema is the way it is, I thought I'd mention that to avoid any discussion about whether it is good or not.
Edit: I want something like the following insert statement as a trigger
INSERT INTO payroll(`batch`,`lineItem`)
(select 'T105',t1.lineItem + 1 from payroll as t1 where batch = 'T105' order by lineItem desc limit 1);
But where 'T105' (the batch id) is hard coded I want the trigger to pick that up from the insert.
So I want to be able to say something like:
INSERT INTO payroll(`batch`)VALUES('T001','T001','T001', 'T002', 'T002', 'T002');
and I would expect to see in the table:
batch lineItem
T001 1
T001 2
T001 3
T002 1
T002 2
T002 3
Getting further:
In trying to implement this I've come up with:
DELIMITER $$
CREATE TRIGGER `co05_test`.`ins_lineItem`
BEFORE INSERT ON `co05_test`.`my_table`
FOR EACH ROW
BEGIN
select lineItem + 1 into #newLineItem from my_table where batch = NEW.batch order by lineItem desc limit 1;
set NEW.lineItem = #newLineItem;
END$$
However when I try...
INSERT INTO `co05_test`.`my_table`(`batch`)VALUES('T001');
I get this error: Column 'lineItem' cannot be null
Which is defined as not being nullable but I though the trigger should set the value!
Solution which I used:
-- Trigger DDL Statements
DELIMITER $$
USE `co05_test`$$
CREATE TRIGGER `co05_test`.`ins_lineItem`
BEFORE INSERT ON `co05_test`.`my_table`
FOR EACH ROW
BEGIN
select count(*) into #batchCount from my_table where batch = NEW.batch;
select lineItem + 1 into #newLineItem from my_table where batch = NEW.batch order by lineItem desc limit 1;
if #batchCount > 0 then
set NEW.lineItem = #newLineItem;
else
set NEW.lineItem = 1;
end if;
END;
$$
Have you tried declaring the variable instead?
DELIMITER $$
CREATE TRIGGER `co05_test`.`ins_lineItem`
BEFORE INSERT ON `co05_test`.`my_table`
FOR EACH ROW
BEGIN
DECLARE newLineItem INT;
SELECT
lineItem + 1 into newLineItem
FROM my_table
WHERE batch = NEW.batch
ORDER BY lineItem DESC
LIMIT 1;
SET NEW.lineItem = newLineItem;
END$$