Ambiguous error in creating BEFORE INSERT trigger - mysql

I have a Reservation table and am creating a BEFORE INSERT trigger that checks whether a user's reservation is already in the database, i.e. prevent him from making duplicate reservations. This is done to signal the front-end that the user is unable to make a duplicate reservation.
However, mySQL raises this error: ERROR 1064 (42000) at line 3: 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 5. For some reason when the body between BEGIN and END is empty, it doesn't raise an error.
CREATE TABLE reservation (
customer_user_id integer,
date integer,
time integer,
name varchar(100)
);
CREATE TRIGGER trigger_name
BEFORE INSERT -- error raised in this line
ON reservation FOR EACH ROW
BEGIN
DECLARE sum INT;
SELECT COUNT(*)
INTO sum
FROM reservation r
WHERE (r.customer_user_id = new.customer_user_id)
AND (r.date = new.date)
AND (r.time = new.time);
IF sum = 0 THEN
INSERT INTO reservation values (new.customer_user_id, new.date, new.time, new.name);
ELSE
RAISE NOTICE 'duplicate'
END IF;
END;
Additionally, could this trigger be a constraint on the table Reservation? E.g. (customer_user_id, date, time) UNIQUE of sorts, which would prevent adding of duplicates, but I am clueless on how to "signal" the front-end which in turn prompts the user that they cannot add a duplicate reservation.
Sorry if some parts of the code might be weird, I'm new to SQL and was taught pSQL.
Thanks in advance!

Related

MySQL: Trying to Create a Trigger Where Another Table is Updated

I'm trying to create a trigger whereby an insertion on one table updates another. This is my SQL Query:
CREATE TRIGGER makePayment AFTER INSERT ON Payments FOR EACH ROW
BEGIN
UPDATE Invoice
SET InvoiceClientPaid = SUM(InvoiceClientPaid + NEW.PaymentAmt)
WHERE InvoiceID = NEW.PaymentInvoiceID;
END;
No matter what I do 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 '' at line 6
I don't think it's related to the SUM, because trying a basic = 1 on the SET command gives me the exact error. There is no '' at line 6 which is very confusing?
If you're entering this query directly into MySQL you will need to change the delimiter prior to the query using (e.g.) DELIMITER //, otherwise it thinks the query ends at the ; at the end of your UPDATE statement. MySQL then sees an END with nothing before it and complains about the nothing (''). So try this:
DELIMITER //
CREATE TRIGGER makePayment AFTER INSERT ON Payments FOR EACH ROW
BEGIN
UPDATE Invoice
SET InvoiceClientPaid = SUM(InvoiceClientPaid + NEW.PaymentAmt)
WHERE InvoiceID = NEW.PaymentInvoiceID;
END; //
DELIMITER ;

MySQL workbench error 1064 when adding trigger

I am new to SQL and more specifically using MySQL Workbench.
I have created a database with two tables Grades and GPAList.
I want to take the average value of every entry in Grades (grouped by student id [sid is the name of the column]) once I have those averages, store them in the GPAList table with their corresponding students. This is intended to trigger every time a new entry is added to Grades.
This is the trigger that I have created:
CREATE DEFINER = CURRENT_USER TRIGGER `ProjectName`.`Grades_AFTER_UPDATE_1` AFTER UPDATE ON `Grades` FOR EACH ROW
BEGIN
SELECT sid, SUM ( CASE grade
when 'A' then 4.0
when 'B' then 3.5
when 'C' then 3.0
when 'D' then 2.5
when 'F' then 1.0
else 0
end
) / COUNT(*) Grades
INTO GPAList
FROM Grades
GROUP BY sid;
END
The error that I am encountering is:
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 1 SQL Statement: CREATE DEFINER = CURRENT_USER TRIGGER
`ProjectName`.`Grades_AFTER_UPDATE_1` AFTER UPDATE ON `Grades` FOR EACH ROW
FOLLOWS `Grades_AFTER_UPDATE`
When I write this code in the workbench, no syntax errors are shown. When I try to apply this trigger, my code is converted to:
DROP TRIGGER IF EXISTS `ProjectName`.`Grades_AFTER_UPDATE_1`;
DELIMITER $$
USE `ProjectName`$$
CREATE DEFINER = CURRENT_USER TRIGGER `ProjectName`.`Grades_AFTER_UPDATE_1` AFTER UPDATE ON `Grades` FOR EACH ROW FOLLOWS `Grades_AFTER_UPDATE`
$$
DELIMITER ;
Only after clicking apply once more do I see the 1064 error listed above. Is there some easy fix that I am missing?
There is a Grades_AFTER_UPDATE that Grades_AFTER_UPDATE_1 is following, so that shouldn't be the problem.
I'm not sure why you would want to store all averages after a single insert, but the correct insert logic is something like this:
INSERT INTO GPALIST(sid, grades)
SELECT sid,
AVG (CASE grade
when 'A' then 4.0
when 'B' then 3.5
when 'C' then 3.0
when 'D' then 2.5
when 'F' then 1.0
else 0
end) as Grades
FROM Grades
GROUP BY sid;
I suspect the trigger would want to access new. somewhere along the way.

Trying to create a transaction in phpmyadmin

Trying to create a transaction in phpmyadmin using the routine panel. I want to do an insert and an update:
START TRANSACTION;
INSERT INTO inventoryitems (item, quantity, userid)
VALUES(item, quantity, userid);
UPDATE users
SET cash = cash - (quantity * unitbuyprice);
COMMIT;
You can see the create/edit routine panel in the screen shot below:
Below is the error I get:
The following query has failed: "CREATE DEFINER=root#localhost PROCEDURE InsertInventoryItem(IN item VARCHAR(255), IN quantity INT, IN userid INT, IN unitbuyprice INT) NOT DETERMINISTIC NO SQL SQL SECURITY DEFINER START TRANSACTION; INSERT INTO inventoryitems (item, quantity, userid) VALUES(item, quantity, userid); UPDATE users SET cash = cash - (quantity * unitbuyprice); COMMIT;"
MySQL said: #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 'INSERT INTO inventoryitems (item, quantity, userid) VALUES(item, quantity, user' at line 3
If I remove the Start Transaction, Commit and either the insert or update then the procedure is fine. IE just a single statement works fine but multiple statements always gives an error.
What am I missing when I want to include multiple statements in a procedure.
I have tried with and without the semi colon delimiter.
This stuff just works with MS SQL. I have created Procedures with hundreds of statements inside before.
Cheers for the Help in advance.
I suggest you add BEGIN and END.
Also note:
A local variable should not have the same name as a table column. If an SQL statement ... contains a reference to a column and a declared local variable with the same name, MySQL currently interprets the reference as the name of a variable.
Reference: https://dev.mysql.com/doc/refman/5.7/en/local-variable-scope.html
If we implement control of transaction within the context of a stored program, we should probably also handle an error condition, and issue the rollback within the stored program. (Personally, I adhere to the school of thought that believes we should handle transaction context outside of the stored procedure.)
The procedure definition would look something like this:
DELIMITER $$
CREATE DEFINER=root#localhost PROCEDURE InsertInventoryItem(
IN as_item VARCHAR(255),
IN ai_quantity INT,
IN ai_userid INT,
IN ai_unitbuyprice INT
)
BEGIN
-- handle error conditions by issuing a ROLLBACK and exiting
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
EXIT PROCEDURE;
END;
START TRANSACTION ;
INSERT INTO inventoryitems (item, quantity, userid)
VALUES (as_item, ai_quantity, ai_userid) ;
UPDATE users u
SET u.cash = u.cash - (ai_quantity * ai_unitbuyprice)
WHERE u.userid = ai_userid ;
COMMIT ;
END$$
DELIMITER ;
--
Note that the update will assign a NULL to cash if either ai_quantity or ai_unitbuyprice is NULL. And we probably want a WHERE clause to limit the rows that will be updated. (Without the WHERE clause, the UPDATE statement will update all rows in the table.)
That's what the statements would look like if I wanted to create the procedure from a normal client, such as the mysql command line, or SQLyog.
MySQL syntax is significantly different than Transact-SQL (Microsoft SQL Server). We just have to deal with that.
As far as "this stuff just works with MS SQL", in all fairness, we should be careful to not conflate MySQL itself with the trouble prone idiot-syncracies of the phpMyAdmin client.

phpMyAdmin create a trigger for deleting a parent row when no child rows exist

In phpMyAdmin I have two tables: listings and textbooks. listings has a foreign key (isbn) from textbooks. I'm trying to create a trigger which, after an entry from listings is deleted, checks to see if there are any other rows in listings with the same isbn as the row that was deleted. If there are no rows with this isbn, then the row with that isbn in textbooks is deleted. This is the code I've tried in phpMyAdmin:
CREATE TRIGGER del_textbook AFTER DELETE ON listings
FOR EACH ROW
BEGIN
IF (SELECT COUNT(*) FROM listings WHERE isbn = (OLD.isbn)) > 0
DELETE FROM textbooks WHERE isbn = (OLD.isbn);
END IF;
END;
It gives this 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 'DELETE FROM textbooks WHERE isbn = (OLD.isbn); END IF; END' at line 5
I also set the delimiter to // before executing this.
Can anybody tell me if my code is formatted correctly, or why this error is occurring? I know that phpmyAdmin is kind of finicky with its formatting. Thanks in advance!
Figured it out. First of all, don't use the SQL query window. Use the Triggers tab. I also forgot the "THEN", so the code looks like:
BEGIN
IF ((SELECT COUNT(*) FROM listings WHERE isbn = OLD.isbn) < 1) THEN
DELETE FROM textbooks WHERE isbn = OLD.isbn;
END IF;
END

Multiplication trigger within a table

I have a table salesOrderItems:
soItemID INT(11) PK
salesOrderID INT(11)
productID INT(11)
cost DECIMAL(7,2)
qty TINYINT(2)
extendedCost DECIMAL(8,2)
Via PHP, user is presented with a form to enter productID (via drop down), that selection then populates the cost field. User then enters qty. extendedCost is not visible on form.
What I want is a trigger that should simply auto-calculate/insert extendedCost (i.e. - multiply cost x qty) and populate extendedCost, but I'm getting 1064 errors.
Here's the trigger - what the hell am I missing??? I swear I've done this 20 times:
DELIMITER $$
DROP TRIGGER IF EXISTS EXTENDEDCOST $$
CREATE TRIGGER EXTENDEDCOST AFTER INSERT ON salesOrderItems FOR EACH ROW BEGIN
UPDATE salesOrderItems
SET extendedCost = (cost * qty)
WHERE soItemID = NEW.soItemID;
END $$
DELIMITER ;
Result:
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 '-db' at line 1
SQL Statement:
USE <my db/schema>
ERROR: Error when running failback script. Details follow.
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 '-db' at line 1
SQL Statement:
USE <my db/schema>
I'm sure it's something stupid, but it's driving me nuts and I'm completely stuck and need extra eyes...
Thanks guys, in advance!
Since you are trying to insert a calculated value, why perform an extra update and not set trigger time BEFORE INSERT :
CREATE TRIGGER EXTENDEDCOST BEFORE INSERT ON salesOrderItems FOR EACH ROW BEGIN
SET NEW.extendedCost = NEW.cost * NEW.qty
END $$
See also this answer mysql 'after insert' trigger to calculate a field based on other fields .