How to use " WITH " clause in MySQL trigger? - mysql

I am trying to write a Mysql query . I am getting some error on WITH clause of select function .
This is the sample query :
CREATE TRIGGER SAMPLE BEFORE INSERT ON SERVER
FOR EACH ROW
BEGIN
IF ((SELECT COUNT(S.ID) FROM SERVER S WITH UR) >= (SELECT L.SERVERS FROM SAMPLE L WHERE L.ID = 1 LIMIT 1)) THEN
SIGNAL SQLSTATE '73550' SET MESSAGE_TEXT='+ID';
END IF;
END;
and i am getting the error :
right syntax to use near 'UR) >= (SELECT L.SERVERS FROM SAMPLE L WHERE L.ID = 1 LIMIT 1))
Is WITH clause doesn't support in Mysql ? Or any other syntax should i use ? Any suggestion would helpful .
update :
Also i am using another query :
CREATE TRIGGER SAMPLE_TRIGGER NO CASCADE BEFORE INSERT ON TABLE_1
FOR EACH ROW
BEGIN
SET NEW.RID = (SELECT ID FROM TABLE_2 WHERE ACTIVE=0 FETCH FIRST 1 ROWS ONLY WITH RS USE AND KEEP EXCLUSIVE LOCKS);
IF (NEW.RID IS NULL) THEN
SIGNAL SQLSTATE '73550' SET MESSAGE_TEXT='+ID';
END IF;
END;
getting another error
right syntax to use near 'LIMIT 1 WITH RS USE AND KEEP EXCLUSIVE LOCKS);
IF (NEW.RID IS NULL) THEN'

In DB2, with ur means "with uncommitted read". This is a locking mechanism in the database, as explained here.
If you are porting code to MySQL, I would not worry about this. So, just remove it:
CREATE TRIGGER SAMPLE BEFORE INSERT ON SERVER
FOR EACH ROW
BEGIN
IF ((SELECT COUNT(S.ID) FROM SERVER S) >= (SELECT L.SERVERS FROM SAMPLE L WHERE L.ID = 1 LIMIT 1)) THEN
SIGNAL SQLSTATE '73550' SET MESSAGE_TEXT='+ID';
END IF;
END;

Related

Trying to resolve a syntax error for MYSQL update trigger

I am trying to create a trigger to update the Project table whenever the Assign table is updated, yet I keep receiving this error: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'END IF
Does anyone have any idea of why I am getting this syntax error? Please note that I am a beginner at this so my SQL statements may be entirely wrong. Also, I know for sure that my query being ran in my IF statement works because I've ran it on its own without being inside a trigger.
delimiter $$
CREATE TRIGGER update_trigger AFTER UPDATE ON Assign
FOR EACH ROW
BEGIN
IF OLD.projNo <> new.projNo THEN
#RUN THIS QUERY TO UPDATE MY TABLE
UPDATE Project p JOIN
(SELECT Project.projNo, COUNT(DISTINCT empid) as numEmployeeAssigned
FROM (Project LEFT JOIN Assign ON Project.projNo=Assign.projNo)
GROUP BY projNo
) as tb
ON p.projNo = tb.projNo
SET p.numEmployeeAssigned = tb.numEmployeeAssigned
#END QUERY
END IF
END$$
delimiter;
You can just increment or decrement the count:
UPDATE Project p
SET p.numEmployeeAssigned = p.numEmployeeAssigned +
(case when p.projNo = new.ProjNo then 1 else -1 end)
WHERE p.projNo IN (old.ProjNo, new.ProjNo) AND
old.ProjNo <> new.ProjNo;
Obviously, your code is missing semi-colons after the UPDATE statement and after the END IF.
However, let me suggest that the UPDATE statement could most likely be simplified. As I understand your code, you want to update the count of employees in Project whenever an employee changes its assignment. If so, there is no need to actually query assign. You can just use conditional logic like this:
CREATE TRIGGER update_trigger AFTER UPDATE ON Assign
FOR EACH ROW
BEGIN
IF OLD.projNo <> new.projNo THEN
UPDATE Project p
SET numEmployeeAssigned = CASE
WHEN projNo = new.projNo THEN numEmployeeAssigned + 1
ELSE numEmployeeAssigned - 1
END
WHERE projNo IN (OLD.projNo, NEW.projNo);
END IF;
END$$
You could even remove the IF statement and put that condition in the query directly:
CREATE TRIGGER update_trigger AFTER UPDATE ON Assign
FOR EACH ROW
BEGIN
UPDATE Project p
SET numEmployeeAssigned = CASE
WHEN projNo = new.projNo THEN numEmployeeAssigned + 1
ELSE numEmployeeAssigned - 1
END
WHERE projNo IN (OLD.projNo, NEW.projNo) AND OLD.projNo <> NEW.projNo
END$$

MySQL Create Trigger Syntax Error (Last Line)

I'm creating a MySQL trigger designed to update various tables with a new value if certain values are changed by an UPDATE query. I keep receiving the following syntax error for this particular trigger:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 29
Line 29 in this case is the line of the END statement.
This is my full code:
DELIMITER $$
CREATE TRIGGER update_selling_prices BEFORE UPDATE ON t1
FOR EACH ROW
BEGIN
DECLARE update_price INT DEFAULT 0;
DECLARE selling_price_1 DECIMAL(10, 3) DEFAULT 0.000;
DECLARE selling_price_2 DECIMAL(10, 3) DEFAULT 0.000;
IF (OLD.rrp_price <> NEW.rrp_price OR OLD.discount_1 <> NEW.discount_1 OR OLD.discount_2 <> NEW.discount_2 OR OLD.net_price <> NEW.net_price OR OLD.markup <> NEW.markup OR OLD.delivery_cost <> NEW.delivery_cost) THEN
SET update_price = (SELECT b.is_auto_update FROM price_categories c INNER JOIN brands b ON b.brand_name = c.brand_name WHERE c.id = NEW.category_id LIMIT 1);
IF (update_price = 1) THEN
IF (NEW.is_bundle = 0) THEN
UPDATE t2 SET temp = 'Fired Single' WHERE id = NEW.id;
ELSE IF (NEW.is_bundle = 1) THEN
UPDATE t2 SET temp = 'Fired Bundle' WHERE id = NEW.id;
END IF;
END IF;
END IF;
END;
$$
DELIMITER ;
The current UPDATE statements are just placeholders for some actual calculations I'll end up doing.
Please note: I use Sequel Pro for most MySQL-related stuff and initially was using their GUI to try and add the trigger - it automatically adds the surrounding code so I would only create everything between the BEGIN and END statements. That also resulted in this same syntax error, so I don't believe it's related to the delimiters like some similar threads I've already found on here. Nevertheless, I've tried adding the full trigger code via a normal query; changing the delimiter syntax - for example END$$, END $$, END; $$ etc.
I've successfully created other triggers with similar syntax, but they do not include the DECLARE syntax.
Where am I going wrong?
The problem is here:
IF (NEW.is_bundle = 0) THEN
UPDATE t2 SET temp = 'Fired Single' WHERE id = NEW.id;
ELSE IF (NEW.is_bundle = 1) THEN
UPDATE t2 SET temp = 'Fired Bundle' WHERE id = NEW.id;
END IF;
Review documentation: https://dev.mysql.com/doc/refman/8.0/en/if.html
MySQL supports ELSEIF and this is different than ELSE IF. If you use ELSEIF, this continues the structure of the IF statement. If you use ELSE IF, it starts a new IF statement, so it should be like this:
IF (NEW.is_bundle = 0) THEN
UPDATE t2 SET temp = 'Fired Single' WHERE id = NEW.id;
ELSE
IF (NEW.is_bundle = 1) THEN
UPDATE t2 SET temp = 'Fired Bundle' WHERE id = NEW.id;
END IF;
END IF;
See that there is a complete IF/THEN/END IF statement within the ELSE block of the outer one?
But you didn't do that, so the END IF applies to the innermost IF statement, and then you're one level off for the rest of the body of the trigger.
When MySQL gets to the end of the whole CREATE TRIGGER statement, if there aren't enough ENDs to balance the blocks you began, MySQL complains with the error you saw.

Sql trigger's query

I am trying to create custom id for my table in the following format
2 random alphabets - 00MaxID
for e.g: AA-001
I have tried writing a query for it but it is not working, this is my first time writing a trigger also writing a complex query such as this.
UPDATED-2
the following query gives me an error near "SELECT count(cus_id) INTO #ct FROM customer;"
CREATE
TRIGGER `id_gen` BEFORE INSERT
ON `testdb`.`customer`
FOR EACH ROW BEGIN
SELECT count(cus_id) INTO #ct FROM customer;
IF #ct < 1000 THEN
SET #cs_id = LPAD(#ct+1, 3, 0 );
ELSE
SET #cs_id = #ct+1;
END IF;
SET NEW.cus_id = CONCAT(CHAR(FLOOR(65 + RAND() * 26),FLOOR(65 + RAND() * 26)),'-',#cs_id);
END;
Error
SQL query: Documentation
CREATE
TRIGGER `id_gen` BEFORE INSERT
ON `testdb`.`customer`
FOR EACH ROW BEGIN
SELECT count(cus_id) INTO #ct FROM customer
MySQL said: Documentation
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 6
Executing with Trigger Section
Answered by #Solarflare.
In the screenshot, you can see that phpmyadmin automatically added code including for each row, which is now twice in the statement (thus the error). Your own code will start with begin.
BEGIN
SELECT count(cus_id)+1 INTO #ct FROM customer;
IF #ct < 1000 THEN
SET #cs_id = LPAD(#ct, 3, 0 );
ELSE
SET #cs_id = #ct;
END IF;
SET NEW.cus_id = CONCAT(CHAR(FLOOR(65 + RAND() * 26),FLOOR(65 + RAND() * 26)),'-',#cs_id);
END;

SQL query runs from IDE but not in phpmyadmin

I've got this SQL code:
CREATE EVENT `update_statistics`
ON SCHEDULE EVERY 1 DAY STARTS '2015-08-24 02:00:00'
ON COMPLETION PRESERVE
DO BEGIN
UPDATE statistics
SET km_traveled = (SELECT sum(km)
FROM archived_trips),
passengers_driven = (SELECT sum(passengers)
FROM archived_trips),
trips_taken = (SELECT count(*)
FROM archived_trips)
WHERE id = 1;
UPDATE statistics
SET co_saved = ((SELECT km_traveled
FROM statistics) * 0.215 * (SELECT passengers_driven
FROM statistics))
WHERE id = 1;
END;
When I run it through the SQL console in PhpStorm - it runs fine and the scheduled task works and so on.
But if I try to run the query directly in phpmyadmin, I get the following error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 13
Line 13 is WHERE id=1;. Honestly, I don't see any syntax problem with the query. Any suggestions?
The delimiter of the query is ';' and ';' is also used in the stored procedure, causing the query to fail.
Add DELIMITER // before the statement and end with // to fix this.
DELIMITER //
CREATE EVENT `update_statistics`
ON SCHEDULE EVERY 1 DAY STARTS '2015-08-24 02:00:00'
ON COMPLETION PRESERVE
DO BEGIN
UPDATE statistics
SET km_traveled = (SELECT sum(km)
FROM archived_trips),
passengers_driven = (SELECT sum(passengers)
FROM archived_trips),
trips_taken = (SELECT count(*)
FROM archived_trips)
WHERE id = 1;
UPDATE statistics
SET co_saved = ((SELECT km_traveled
FROM statistics) * 0.215 * (SELECT passengers_driven
FROM statistics))
WHERE id = 1;
END; //
DELIMITER ;
With PHPstorm, sending multiple queries in one go is probably disabled, causing MySQL to ignore the delimiter.
You must set the DELIMITER to other char. else they cant find out the end of the EVENT.
DELIMITER //
CREATE EVENT `update_statistics`
ON SCHEDULE EVERY 1 DAY STARTS '2015-08-24 02:00:00'
ON COMPLETION PRESERVE
DO BEGIN
UPDATE statistics
SET km_traveled = (SELECT sum(km)
FROM archived_trips),
passengers_driven = (SELECT sum(passengers)
FROM archived_trips),
trips_taken = (SELECT count(*)
FROM archived_trips)
WHERE id = 1;
UPDATE statistics
SET co_saved = ((SELECT km_traveled
FROM statistics) * 0.215 * (SELECT passengers_driven
FROM statistics))
WHERE id = 1;
END//
Shot in the dark, but try removing the semicolon after END.

Loop in a MySql stored procedure error code 1064

I'm reasonably new to writing MySQL stored procedures, and I'm trying to get my head around using loops and variables.
I have a table with a column called STAT_NAME, where several rows could have the same value for that column. I want to create a temporary column which numbers the occurrences of each STAT_NAME value, so for example first time STAT_NAME is "stat A", set STAT_COUNT to 1, 2nd time 2 etc. And then start again at 1 for "stat B" and so on.
I've got as far as creating the the temporary table with an empty column called STAT_COUNT, and sorted the table by STAT_NAME.
I've then tried to loop through all the rows and set STAT_COUNT accordingly. However, I get the following error:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '#counting,1) THEN SET #STAT_NAME_CURR = (SELECT #STAT_NAME FROM tmp1 LIMIT #'
Is anyone able to explain why what I've written is not OK? I think it would be fine if I used a system variable instead of #counting, and I don't understand why. I've tried googling the problem but not getting anywhere!
cheers.
DROP PROCEDURE IF EXISTS collate_stats;
delimiter //
CREATE PROCEDURE collate_stats()
begin
create temporary table tmp1 engine=memory
SELECT STAT_NAME, STAT, '' AS STAT_COUNT
FROM performance_testing_stats.20131014
ORDER BY STAT_NAME;
-- stat name that we are currently looking at
SET #STAT_NAME_CURR := "";
-- number of times this name has been found so far
SET #STAT_NAME_COUNT := 0;
-- Use to loop through all rows
SET #n := (SELECT COUNT(*) FROM tmp1);
-- Row reached so far
SET #counting := 0;
WHILE #counting < #n DO
-- IF #STAT_NAME_CURR is not equal to the STAT_NAME for the current row,
-- THEN set #STAT_NAME_CURR to STAT_NAME value and reset #STAT_NAME_COUNT
-- ELSE just increment #STAT_NAME_COUNT
IF #STAT_NAME_CURR <> (SELECT #STAT_NAME FROM tmp1 LIMIT #counting,1) THEN
SET #STAT_NAME_CURR = (SELECT #STAT_NAME FROM tmp1 LIMIT #counting,1);
SET #STAT_NAME_COUNT = 0;
ELSE
SET #STAT_NAME_COUNT = #STAT_NAME_COUNT + 1;
END IF;
-- Set STAT_COUNT for current row to value of #STAT_NAME_COUNT
UPDATE tmp1 SET STAT_COUNT = #STAT_NAME_COUNT WHERE STAT_NAME = #STAT_NAME_CURR AND STAT_COUNT = '' LIMIT 1;
-- Move to next row
SET #counting = #counting + 1;
END WHILE;
select * from tmp1;
END //
delimiter ;
You might want to look into using cursors instead of the while loop.
However, you could probably accomplish what you are trying to do with a simple GROUP BY query:
SELECT STAT_NAME, STAT, COUNT(1) as STAT_COUNT
FROM performance_testing_stats.20131014
GROUP BY STAT_NAME, STAT
ORDER BY STAT_NAME, STAT;
Unless I'm missing something about what you are doing.