Why is this mysql trigger syntax is wrong? - mysql

There are two tables involved in this question: Register(eid, sid, price, rating) and Event (eid, ename, edescription, edate, memprice, nonmemprice, maxpeople).
I want to create a trigger that is monitoring the Register that if the number of registrations of any Event exceed the 80% of the maximum people allowed in such event, we arise the non-memberprice of this event by 50%.
So far I have something like this
delimiter//
create trigger price_change
after insert on Register for each row begin
DECLARE counts INT;
DECLARE maxpeople INT;
set counts = (select count(sid) from Register
JOIN Event ON Register.eid = Event.eid
where eid = new.eid);
set maxpeople = (select maxpeople from Event where Event.eid =
new.eid);
if counts >= 0.8 * maxpeople
then
update Event set nonmemprice = nonmemprice * 1.5 where eid
= new.eid;
end if;
end//
delimiter;
I'm still learning how to write trigger and I ended up with this trigger. I tried to add it into MySQL but it said there are syntax errors basically everywhere of this trigger. I'm really confused. It would be appreciated if anyone help me with this.

The error is right at the beginning. Use a space in between:
delimiter //
^--------------here
And at the end of course too: delimiter ;

Related

Stored Procedure ahowing 'lock wait timeout exceeded try restarting transaction in mysql stored procedure' error?How to handel it?

Hello guys i am trying to validate otp verification manually.for that i have written this stored procedure .When i started this code was working fine but after some time its start giving error.It was taking too long time to execute approx 50sec and after that it was giving the error lock wait timeout.So can anyone tell me why its giving such error and how to resolve it?
CREATE DEFINER=`xxxxx`#`xxxx` PROCEDURE `new_mobile_authentication`(
IN in_macID VARCHAR(500),IN in_otp INT(5),OUT in_msg VARCHAR(100))
BEGIN
DECLARE userCount INT(10);
DECLARE emailID VARCHAR(100);
DECLARE mobileNumber BIGINT(11);
DECLARE checkmatched INT(5);
DELETE FROM mob_user WHERE NOW()>end_time;
SELECT COUNT(*),email,mobile,otp into userCount,emailID,mobileNumber,checkmatched FROM mob_user WHERE mac_id=in_macID ;
SET #checkEmailPresent=(SELECT COUNT(*) FROM table A WHERE email_id=emailID);
IF(userCount!=0 AND #checkEmailPresent!=0)THEN
IF(checkmatched=in_otp)THEN
UPDATE table A SET auth='YES',mac_id=in_macID,mobile_num=mobileNumber WHERE email=emailID;
SET #affRow=(SELECT ROW_COUNT());
DELETE FROM mob_user WHERE mac_id=in_macID;
SELECT #affRow AS affRow,email FROM table A WHERE mac_id=in_macID;
ELSE
SELECT 'invalid otp' INTO in_msg;
END IF;
ELSEIF(userCount!=0 AND #checkEmailPresent=0)THEN
IF(checkmatched=in_otp)THEN
INSERT INTO table A(email,mobile_num,mac_id) VALUE (emailID,mobileNumber,in_macID,);
SET #affRow=(SELECT ROW_COUNT());
DELETE FROM mob_user WHERE mac_id=in_macID;
SELECT #affRow AS affRow,email FROM table A WHERE mac_id=in_macID;
ELSE
SELECT 'invalid otp' INTO in_msg;
END IF;
ELSE
SELECT 'session expired' INTO in_msg;
END IF;
END
Fix timeouts by adding indexes and/or reformulating queries.
mob_user needs INDEX(end_time) and INDEX(mac_id).
SELECT COUNT(*), this, that ... without a GROUP BY does not makes sense. Nor will it work right with a GROUP BY. What were you expecting??
SET #checkEmailPresent=(SELECT COUNT(*) FROM table A WHERE email_id=emailID) can be rewritten SELECT #checkEmailPresent := COUNT(*) FROM table A WHERE email_id=emailID). Note the :=. That table needs INDEX(email_id).
IF(checkmatched=in_otp)THEN does not make sense since checkmatched is nowhere set. No that SELECT does not set it.
What is ROW_COUNT()? I don't think it is a MySQL function.

MySQL Stored Procedure - Nested loop at fault?

I have a medium sized stored procedure going on here below. My problem is that it doesn't do anything and I have no idea why.
1.) First of all, the code:
DROP PROCEDURE IF EXISTS deleteabundant_fixshared_shiftResources;
DELIMITER //
CREATE PROCEDURE deleteabundant_fixshared_shiftResources ()
BEGIN
DECLARE finish_flag BOOLEAN DEFAULT FALSE;
DECLARE id INT(11);
DECLARE startTime DATETIME;
DECLARE endTime DATETIME;
DECLARE shid INT(11);
DECLARE resid INT(11);
DECLARE id_inner INT(11);
DECLARE startTime_inner DATETIME;
DECLARE endTime_inner DATETIME;
DECLARE shid_inner INT(11);
DECLARE resid_inner INT(11);
DECLARE cr130 CURSOR FOR SELECT shift_resource_id, start_date, end_date, shift_id, resource_id FROM temp_shift_resource;
DECLARE cr131 CURSOR FOR SELECT shift_resource_id, start_date, end_date, shift_id, resource_id FROM temp_shift_resource;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finish_flag = TRUE;
START TRANSACTION;
OPEN cr130;
OPEN cr131;
OUTERLOOP: LOOP
FETCH cr130 into id, startTime, endTime, shid, resid;
IF finish_flag THEN LEAVE OUTERLOOP; END IF;
INNERLOOP: LOOP
FETCH cr131 INTO id_inner, startTime_inner, endTime_inner, shid_inner, resid_inner;
IF finish_flag THEN LEAVE INNERLOOP; END IF;
IF (id!=id_inner) THEN
IF (resid=resid_inner AND shid_inner!=9) THEN
-- logic to determine if the dates are wrong:
IF (startTime<=startTime_inner AND endTime>=endTime_inner) THEN
INSERT INTO repairchange ( shift_resource_id, changetype, shift_id, resource_id, start_date, end_date )
VALUES ( id_inner, "FD", shid_inner, resid_inner, startTime_inner, endTime_inner );
DELETE FROM temp_shift_resource WHERE shift_resource_id = id_inner;
ELSEIF (endTime>=endTime_inner AND startTime<=endTime_inner) THEN
INSERT INTO repairchange ( shift_resource_id, changetype, shift_id, resource_id, start_date, end_date )
VALUES ( id_inner, "FU", shid_inner, resid_inner, startTime_inner, endTime_inner );
UPDATE temp_shift_resource set endTime_inner=(startTime - INTERVAL 1 DAY) where shift_resource_id = id_inner;
ELSEIF (startTime<=startTime_inner AND endTime>=startTime_inner) THEN
INSERT INTO repairchange ( shift_resource_id, changetype, shift_id, resource_id, start_date, end_date )
VALUES ( id_inner, "FU", shid_inner, resid_inner, startTime_inner, endTime_inner );
UPDATE temp_shift_resource set startTime_inner=(endTime + INTERVAL 1 DAY) where shift_resource_id = id_inner;
END IF;
END IF;
END IF;
END LOOP INNERLOOP;
SET finish_flag = FALSE;
END LOOP OUTERLOOP;
CLOSE cr130;
CLOSE cr131;
COMMIT;
END //
DELIMITER ;
call deleteabundant_fixshared_shiftResources();
2.) Description of what I want to do:
Basically, I have a table full of workshifts. Due to code bugs, some of these shifts have a wrong date assigned to them, and I have to fix the database.
I have to run through the whole table, and compare the rows that are assigned to the same resource_id, which represents a person. So if a person has two shifts that look like (2016-05-10 to 2016-05-20) and (2016-05-15 to 2016-05-23) for example, I have to fix it so that one of them will be trimmed to (2016-05-10 to 2016-05-14) and (2016-05-15 to 2016-05-23).
A shift that is a nightshift, marked as shift_id=9, must not be modified at all.
I insert rows into the repairchange table if a change or a deletion has been made
3.) The procedure runs, but does nothing. I have examples in the database for wrong rows, one example is the one I wrote above. I suspect it is the nested loop, because I want to loop and fetch through the same table, but I haven't found anything on that.
I got the message
0 row(s) affected, 1 warning(s): 1329 No data - zero rows fetched, selected, or processed
but I have seen this before and my stored procedures have worked even though they output this warning.
Any ideas or tips are welcome. Thank you for your time!
I figured it out, after quite some debugging:
I opened the cursors before both of the loops. This meant that after the first walk-through of the inner loop, the cursor was standing at +1 of the LAST row of the table, and when the new outer loop iteration started the second inner loop iteration, the cursor was still at the end position.
Thus it did not run. I replaced the inner-cursor opening and closing into the outer loop, and now it works properly.

How to transform/migrate a mysql trigger to a Sql Server Trigger

I did a trigger in mysql to shoot alerts always an input value was less than the set value. But now I need it is done in SQL SERVER.
I would be grateful if someone could help me transform mysql trigger to a SQL Server trigger.
Thanks to all at once.
My trigger is:
DELIMITER $$
create TRIGGER alert
AFTER INSERT ON records
FOR EACH ROW
begin
Set #comp=0;
Set #tempmax=0;
Set #tempmin=0;
select lim_inf_temp into #tempmin from sensores where idSensor=NEW.idSensor;
Set #maxidAlarme=0;
if (CAST(NEW.Temperatura AS UNSIGNED)<#tempmin) then
SELECT MAX(idAlarme) into #maxidAlarme FROM alarmes;
SET #maxidAlarme=#maxidAlarme+1;
INSERT INTO alarmes(idAlarme,descricao_alarme, idRegisto) VALUES (#maxidAlarme,"inserted below the normal temperature",New.idRegisto);
INSERT INTO sensores_tem_alarmes(idSensor,idAlarme,dataAlarme) VALUES (NEW.idSensor,#maxidAlarme,NOW());
set #comp=+1;
end if;
set #id_sensores_em_alerta=1;
SELECT MAX(id_sensores_em_alerta) into #id_sensores_em_alerta FROM sensores_em_alerta;
INSERT INTO sensores_em_alerta(id_sensores_em_alerta, idSensor, idAlarme, data_registo, numerosensoresdisparados) VALUES (id_sensores_em_alerta,NEW.idSensor, #maxidAlarme, NOW(), #comp);
end $$;
DELIMITER ;
I've tried to make the trigger in SQL Server, but as the script is different and I'm getting many difficulties to do the right way.
My attempt that was not going at all well:
CREATE TRIGGER Alert ON registos AFTER INSERT AS
BEGIN
DECLARE #comp decimal= 0
DECLARE #tempmax decimal= 0
DECLARE #tempmin decimal= 0
DECLARE #current_max_idAlarme int = (SELECT MAX(IdAlarme) FROM alarmes)
-- Insert into alarmes from the inserted rows if temperature less than tempmin
INSERT alarmes (IdAlarme, descricao_alarme, idRegisto)
SELECT
ROW_NUMBER() OVER (ORDER BY i.idRegisto) + #current_max_idAlarme,
'temp Error',
i.idRegisto
FROM
inserted AS i
WHERE
i.Temperatura < #tempmin
END
But dont do anything.
Dont create data on table alarmes :S
Does anyone could help me please. I would be eternally grateful.
Many Greetings and thank you all.
First of all, MSSQL doesn't have the option FOR EACH ROW, so it treats multiple inserted rows at once as a set. You will therefore have to insert the values into a table variable.
Unfortunately I do not know much MySQL actually, but I believe this is a starting point?
CREATE TRIGGER ALERT
ON records
AFTER INSERT
AS
BEGIN
DECLARE #comp INT;
DECLARE #tempmax INT;
DECLARE TABLE #tempmin (tempmin INT);
INSERT INTO #tempmin
SELECT s.lim_inf_temp FROM sensores s WHERE s.idSensor IN (inserted.idSensor);
--rest of the code
I'm going to post this code against my better judgement - redesign the tables is better than this hack.
This uses a ROW_number() to virtualise a surrogate identity key for the alarmes table. This is a 'bad plan' (tm).
Also the answer is partial - it doesn't do everything your question asked for -- I hope it gets your further along the road. Use it as a guide for how to interact with the virtual INSERTED table. Good luck
CREATE TRIGGER Alert ON records AFTER INSERT AS
BEGIN
DECLARE #comp INT = 0
DECLARE #tempmax INT = 0
DECLARE #tempmin INT = 0
-- get the max current id.
-- note that this is EXTREMELY unsafe as if two pieces of code are executing
-- at the same time then you *will* end up with key conflicts.
-- you could use SERIALIZABLE.... but better would be to redisn the schema
DECLARE #current_max_idAlarme = (SELECT MAX(IdAlarme) FROM alarmes)
-- Insert into alarmes from the inserted rows if temperature less than tempmin
INSERT alarmes (IdAlarme, descricao_alarme, idRegisto)
SELECT
ROW_NUMBER() OVER (ORDER BY i.idRegisto) + #current_max_idAlarme,
'temp Error',
i.idRegisto
FROM
inserted AS i
WHERE
i.Temperatura < #tempmin
END

Assigning the value from a select statement to a vairable in MySQL

I'm fairly new to SQL in general and even more so to MySQL and I've hit a stumbling block. I'm attempting to use a procedure to copy the value of one field to another if the original field is not null, this procedure is then called by triggers whenever the table is updated or has a new row inserted into it. Here is what I have so far:
-- WORK_NOTES_PROCEDURE - This copies the contents of the estimate notes to the work order notes if the original estimate had any notes with it.
DROP PROCEDURE IF EXISTS 'WORK_NOTES_PROCEDURE';
DELIMITER $$
CREATE PROCEDURE WORK_NOTES_PROCEDURE()
BEGIN
DECLARE var_temp VARCHAR(50);
SET var_temp := (SELECT ESTIMATE_NOTES FROM ESTIMATES WHERE ESTIMATES.ESTIMATE_NUMBER = WORK_ORDERS.ESTIMATE_NUMBER);
IF var_temp IS NOT NULL THEN
UPDATE WORK_ORDERS SET WORK_ORDER_NOTES = var_temp WHERE WORK_ORDERS.ESTIMATE NUMBER = ESTIMATES.ESTIMATE_NUMBER;
END IF;
END$$
DELIMITER ;
Absolutely any help would be appreciated, the error I'm getting is a syntax error for the line where I'm assigning a value to var_temp.
try,
SET var_temp = (SELECT ESTIMATE_NOTES
FROM ESTIMATES INNER JOIN WORK_ORDERS
ON ESTIMATES.ESTIMATE_NUMBER = WORK_ORDERS.ESTIMATE_NUMBER
LIMIT 1);

MYSQL Procedures run, but return 0 rows affected

I call a procedure, it runs, and the console says "0 rows affected". Is this normal behavior for a MySQL procedure ?
The procedures are clearly doing what they should. One procedure has 2 insert statements, another has an insert and update statement, and I've seen the results with my own eyes. There are indeed rows being affected.
I'm not sure that I would use that result later on, but it seems like I'd want to get an accurate response from my DB whether or not anything was updated, especially when its expected.
Thoughts ?
MySQL 5.5 if it matters, and the procedures use transactions over auto-committed statements.
CREATE DEFINER=`root`#`localhost` PROCEDURE `create_issue`(user_id SMALLINT, title varchar(255), body LONGTEXT)
BEGIN
DECLARE MYUSERID SMALLINT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END;
START TRANSACTION;
INSERT INTO tracker.issue (user_id, title, body, creation_date, last_mod_date) values (user_id, title, body, CURDATE(), CURDATE());
UPDATE user_activity SET last_new_issue = CURDATE(), post_count = post_count + 1 WHERE user_activity.user_id = user_id;
COMMIT;
END
Edited to show the actual query. Also I've been searching and as best as I can tell this is a known issue over a year and a half old. So I suppose this one can be closed.
the "0 rows affected" response is for the last statement executed in the stored procedure.
usually i track the number of rows effected by manually counting them into session variables
DELIMITER $$
CREATE PROCEDURE `create_issue`(user_id SMALLINT, title varchar(255), body LONGTEXT)
BEGIN
DECLARE MYUSERID SMALLINT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END;
SET #inserted_rows = 0;
SET #updated_rows = 0;
START TRANSACTION;
INSERT INTO tracker.issue (user_id, title, body, creation_date, last_mod_date) values (user_id, title, body, CURDATE(), CURDATE());
SET #inserted_rows = ROW_COUNT() + #inserted_rows;
UPDATE user_activity SET last_new_issue = CURDATE(), post_count = post_count + 1 WHERE user_activity.user_id = user_id;
SET #updated_rows = ROW_COUNT() + #updated_rows;
COMMIT;
END
$$
the session variables can then be read after the SP was executed.
i am not sure if it is possible to override the response from the ROW_COUNT() function by setting a value to a variable,
I guess this is a reported bug. May be a good question for MySQL mailing list/forum. http://bugs.mysql.com/bug.php?id=44854
Something definitely isn't right. A sproc should still return the number of rows affected if there are multiple inserts occurring. I'm using the same version of MySQL and this works fine for me.
Are you sure you're not doing something like that
...SET col1='value1' AND col2='value2'...
instead of
...SET COL1='value1', col2='value2'...
Could you post your stored procedure?