I need to delete records from a staging table in a stored procedure. I then need to insert records into the same table. This must be done prior to using a cursor that loops through the records.
DELIMITER //
CREATE PROCEDURE Get_Employee_Records()
BEGIN
DECLARE rollingSum INT DEFAULT 0;
DECLARE theMonth varchar(3);
-- Delete & insert on Employee must be done prior to the select
DECLARE mycursor CURSOR FOR SELECT Tgrowth,TYear,myMONTH FROM Employee;
-- cursor body here
CLOSE mycursor;
END //
DELIMITER ;
When i place my insert & delete statements in the commented section i get
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 'DECLARE mycursor CURSOR FOR SELECT Tgrowth,TYear,myMONTH FROM Employee' at line 63
Where would be the right place to place the insert & delete sql in the procedure. I could probably do this in a separate procedure but I want to know if i am missing something here.
In a begin...end block declarations must appear before any other code so
wrap the cursor section in a begin..end like so (btw you need to fix the code).
begin
DECLARE mycursor CURSOR FOR SELECT Tgrowth,TYear,myMONTH FROM Employee;
-- cursor body here
open mycursor;
CLOSE mycursor;
end;
There is almost never a reason to use cursors in sql - are you sure your approach is appropriate?
I am not very familiar with MYSQL but I think you DELETE and INSERT should come after Cursor declaration and and before opening and closing the cursor.
Related
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.
I have this code here:
CREATE TRIGGER testTrigger
AFTER INSERT ON users
BEGIN
DECLARE #uid VARCHAR(60)
SET #uid = (SELECT userid FROM inserted)
INSERT INTO user_locations (id,uid,lat,lng) VALUES (0,#uid,5.0,5.0)
END;
The idea is to insert generated user id into other table alongside some other data as soon as it hits the first 'users' table but phpMyAdmin gives this 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
BEGIN
DECLARE #uid VARCHAR(60)
SET #uid = (SELECT userid FROM inserted)
at line 3
Can someone clarify why this trigger is bad?
I see four problems:
You have to use DELIMITERs so that your able to finish the commands with a semicolon as usual.
FOR EACH ROW is missing.
Use new.uid to access the recently inserted uid.
I'd also suggest using procedure variables instead of session-specific user-defined #variables, the latter ones being loosely typed and not declared as you've done.
But you don't even have to declare a variable. If you don't use phpMyAdmin:
DELIMITER //
CREATE TRIGGER testTrigger
AFTER INSERT ON users FOR EACH ROW
BEGIN
INSERT INTO user_locations (id,uid,lat,lng) VALUES (0,new.uid,5.0,5.0);
END//
DELIMITER ;
Check this answer about delimiter and the MySQL 5.7 docs on triggers and this answer about variables.
Edit, I overread you're using phpMyAdmin:
I don't use phpMyAdmin. But you can (stolen from here)
In phpMyAdmin, select the database that you want to work with.
Go to the SQL tab at the top of the page.
In the "Run SQL query/queries on database" form, change the Delimiter to $$. (Located in a small box at the bottom of the form)
Enter your SQL trigger into the main dialog box on the form. The correct syntax is as follows:
CREATE TRIGGER testTrigger
AFTER INSERT ON users FOR EACH ROW
BEGIN
INSERT INTO user_locations (id,uid,lat,lng) VALUES (0,new.uid,5.0,5.0);
END;$$
Hit "GO" with Super privilege.
Is it possible to write compound statements in if condition -mysql ?
It is returning an error for me like:
[Err] 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 'DECLARE n INT unsigned DEFAULT 0;
DECLARE i INT unsigned DEFAULT 0;
DECL' at line 40
Sombody please help
Here is the query I am using
...........................................
IF(tarif='LT')
THEN
CREATE TABLE costSlabs SELECT `Start`,`End`,Cost FROM energy_slabs where SiteId=NEW.SiteID and `Start` < totalUnits;
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE newStart INT;
DECLARE newEnd INT;
DECLARE newCost DOUBLE;
DECLARE finalCost DOUBLE DEFAULT 0;
SELECT COUNT(*) FROM costSlabs INTO n;
SET i=0;
WHILE i<n DO
SELECT `Start`, `End`,Cost INTO newStart,newEnd,newCost FROM costSlabs LIMIT i,1 ;
IF(newEnd<totalUnits)
THEN
SET finalCost = finalCost + ((newEnd-newStart) * newCost);
ELSE
...........................................
The IF statement is valid within the context of a MySQL stored program (stored procedure, function or trigger). Outside of the context of a MySQL stored program, it isn't a valid SQL statement.
We're not seeing the context of these statements, but based on the reference to NEW. in the SQL SELECT, without any table or table alias named NEW, I'll assume that this SQL is in the context of a CREATE TRIGGER statement.
I suspect that the problem you are encountering is due to the semicolon delimiter, which effectively ends the CREATE TRIGGER statement. In order to create a trigger that includes semicolon characters, it's necessary to specify a different statement delimiter. For example:
DELIMITER $$
CREATE TRIGGER mytrig
BEFORE INSERT ON mytable
FOR EACH ROW
BEGIN
SET NEW.col1 = 'foo';
SET NEW.col2 = 'bar';
END$$
DELIMITER ;
The first statement specifies that $$ will be used as the delimiter to end a statement. With that set, the statements following will be read together as a single statement, until a $$ delimiter is encountered. That will end the statement, and allow it be executed. This basically prevents the semicolons within the trigger body from prematurely "ending" the statement.
Once the statements are completed, you can change the delimiter back to a semicolon.
The block of SQL text posted in the question is invalid on its own. I suspect that the syntax error is being returned from the execution of a CREATE TRIGGER statement, but that's just a guess, since there's not enough context in the question to make a conclusion.
Also, I believe that within a MySQL stored program (such as a TRIGGER), all of the DECLARE statements must appear before other statements, such as CREATE TABLE.
This is a very simple MySQL stored procedure. Cursor "commission" has only 3000 records, but the procedure call takes more than 30 seconds to run. Why is that?
DELIMITER //
DROP PROCEDURE IF EXISTS apply_credit//
CREATE PROCEDURE apply_credit()
BEGIN
DECLARE done tinyint DEFAULT 0;
DECLARE _pk_id INT;
DECLARE _eid, _source VARCHAR(255);
DECLARE _lh_revenue, _acc_revenue, _project_carrier_expense, _carrier_lh, _carrier_acc, _gross_margin, _fsc_revenue, _revenue, _load_count DECIMAL;
DECLARE commission CURSOR FOR
SELECT pk_id, eid, source, lh_revenue, acc_revenue, project_carrier_expense, carrier_lh, carrier_acc, gross_margin, fsc_revenue, revenue, load_count FROM ct_sales_commission;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DELETE FROM debug;
OPEN commission;
REPEAT
FETCH commission INTO
_pk_id, _eid, _source, _lh_revenue, _acc_revenue, _project_carrier_expense, _carrier_lh, _carrier_acc, _gross_margin, _fsc_revenue, _revenue, _load_count;
INSERT INTO debug VALUES(concat('row ', _pk_id));
UNTIL done = 1 END REPEAT;
CLOSE commission;
END//
DELIMITER ;
CALL apply_credit();
SELECT * FROM debug;
If you select some datas, and insert into another table, you can do this:
INSERT INTO debug
SELECT concat('row ', _pk_id)
FROM ct_sales_commission;
It's faster than using a cursor.
Some minor turning:
Remove all indexes on the table debug.
Replace the DELETE FROM into TRUNCATE TABLE.
Add DELAYED to the insert statement.
INSERT DELAYED INTO ... VALUES(....)
The database is hosted in a data centre very far away from my MySQL client.
Connected to a MySQL client which is closely located with the MySQL server makes execution time almost 60 times faster (it takes less than one second for the procedure to complete).
I suspect that MySQL client CLI has an issue handling a remote data connection like that.
Does SQL-fiddle facilitate execution of triggers/stored procedures?
I have been unable to execute even the simplest form of stored procedure on sqlfiddle
DELIMITER $$
DROP PROCEDURE IF EXISTS myProc $$
CREATE PROCEDURE myProc()
BEGIN
END$$
DELIMITER ;
Sqlfiddle does not allow executing this(above) sql in build schema, but allows create table etc
Note: The same syntax is working for me on my localhost using wamp with mysql 5.5.24
Can anyone guide please?
Instead of using the delimiter option (which is not a real SQL statement, but rather only a command for the mysql command prompt) use the "Query Terminator" option on SQL Fiddle to establish your delimiter.
For example:
http://sqlfiddle.com/#!2/88fcf
Note the // dropdown below the schema box? That's the SQL Fiddle equivalent to the mysql DELIMITER command.
Longer example with queries in the stored procedure (note that within the stored procedure, ; is still used as a delimiter):
http://sqlfiddle.com/#!9/4db78
Full disclosure: I'm the author of SQL Fiddle.
I couldn't get this answer to work on sql fiddle, but found db-fiddle, and it seems to work.
Example in DB Fiddle
If the above doesn't work for some reason, do the following
Go here: https://www.db-fiddle.com/
Enter the following SQL on the left, and SELECT * FROM tblTest; on the right.
Select "MySql 5.7" or whatever in dropdown.
Click "Run"
DELIMITER //
CREATE TABLE tblTest (col1 INT)//
INSERT INTO tblTest VALUES (9)//
CREATE PROCEDURE dowhile()
BEGIN
DECLARE v1 INT DEFAULT 3;
WHILE v1 > 0 DO
INSERT INTO tblTest VALUES(v1);
SET v1 = v1 - 1;
END WHILE;
END//
INSERT INTO tblTest VALUES (8)//
select * from tblTest//
call dowhile()//
select * from tblTest//
DELIMITER ;