MySql syntax error on procedure parameter - mysql

I am trying to write a simple procedure but am encountering a syntax error at the first parameter. As best I can tell I'm following the syntax of CREATE PROCEDURE correctly.
I am limited to accessing my database with phpMyAdmin. Here is the create script I'm trying to run:
DROP PROCEDURE IF EXISTS product_index_swap/
CREATE PROCEDURE product_index_swap (#id INT, #oldIndex INT, #newIndex INT)
BEGIN
DECLARE #swapID;
SET #swapID = (SELECT `id` FROM `product` WHERE `order_index` = #newIndex LIMIT 1);
UPDATE `products` SET `order_index` = (CASE WHEN `id` = #id THEN #newIndex
WHEN `id` = #swapID THEN #oldIndex END)
WHERE `id` IN (#id, #swapID);
END
I am using the option on phpMyAdmin to change the delimiter to /.
I receive a syntax error "near '#id INT, #oldIndex INT....". I thought I may encounter more delimiter errors since I'm not entirely clear on the scope of them. I believe if that was the problem the error would be on a new line in the procedure when it failed to understand a semicolon, not at the parameters declaration.

You're using the Microsoft SQL Server convention of putting # before all the parameters and local variables. MySQL doesn't do this.
In MySQL syntax, procedure parameters have no sigil.
Also parameters are typically declared IN or OUT or INOUT.
CREATE PROCEDURE product_index_swap (IN id INT, IN oldIndex INT, IN newIndex INT)
BEGIN
DECLARE swapID;
...
MySQL variables that have the # sigil are session variables.
See also:
https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
https://dev.mysql.com/doc/refman/5.7/en/declare-local-variable.html
https://dev.mysql.com/doc/refman/5.7/en/set-variable.html

In MySQL, the #var variables are session level variables.
Use normal variables without the # and make sure you do not have conflict with column names:
CREATE PROCEDURE product_index_swap (in_id INT, in_oldIndex INT, in_newIndex INT)
BEGIN
DECLARE v_swapID int;
SELECT id into v_swapID
FROM product
WHERE order_index = in_newIndex
LIMIT 1;
UPDATE products
SET order_index = CASE WHEN id = in_id THEN in_newIndex
WHEN id = v_swapID THEN in_oldIndex
END
WHERE id IN (in_id, v_swapID);
END

Related

MySQL PROCEDURE using IF Statement with #Parameter Not Working

Why is the data not being inserted on the table when I execute the procedure, what seems to be lacking with the code?
I'm testing the procedure on phpMyAdmin > myDatabase > Procedures "Routines Tab" and clicking "Execute", prompts with a modal and ask for the values of "#idproc and #nameproc.
I tried with just the INSERT code it works, but when I add the IF condition it doesn't work.
Using XAMPP 8.0.3,
10.4.18-MariaDB
DELIMITER $$
CREATE DEFINER=`root`#`localhost:3307` PROCEDURE `testproc`(IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
IF #idproc = 0 THEN
INSERT INTO testproc(
id,
name)
VALUES(
#idproc,
#nameproc
);
ELSE
UPDATE testproc
SET
id = #idproc,
name = #nameproc
WHERE id = #idproc;
END IF;
SELECT * FROM testproc;
END$$
DELIMITER ;
You mix local variables (their names have not leading #) and user-defined variables (with single leading #). This is two different variable types, with different scopes and datatype rules. Procedure parameters are local variables too.
So when you use UDV which was not used previously you receive NULL as its value - and your code works incorrectly. Use LV everywhere:
CREATE DEFINER=`root`#`localhost:3307`
PROCEDURE `testproc` (IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
IF idproc = 0 THEN
INSERT INTO testproc (name) VALUES (nameproc);
ELSE
UPDATE testproc SET name = nameproc WHERE id = idproc;
END IF;
SELECT * FROM testproc;
END
You do not check does specified idproc value exists in the table. If it is specified (not zero) but not exists then your UPDATE won't update anything. Assuming that id is autoincremented primary key of the table I recommend to use
CREATE DEFINER=`root`#`localhost:3307`
PROCEDURE `testproc` (IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
INSERT INTO testproc (id, name)
VALUES (idproc, nameproc)
ON DUPLICATE KEY
UPDATE name = VALUES(name);
SELECT * FROM testproc;
END
If specified idproc value exists in id column the row will be updated, if not then the new row will be inserted.
Additionally - I recommend you to provide NULL value instead of zero when you want to insert new row with specified nameproc value. NULL always cause autoincremented primary key generation whereas zero needs in specific server option setting.

Calling a function in MySQL database with table alias

Currently I have used imported a MySQL database in my current environment.My MySQL version is 5.6.x. Now I have certain database functions that I have to use in my java application. The problem is stated below:
MySQL database is EMPLOYEE.
MySQL function FN_GET_USER_CODE(userID INT) has used table
alias (EMPDTL) for table EMP_DETAILS_COMPANY and used some joins in function definition.
When I try to call the function via command
select FN_GET_USER_CODE(234599), It says Table EMPLOYEE.EMPDTL does not exist.
Error Code: 1146
Table 'EMPLOYEE.EMPDTL' doesn't exist
Function Definition
CREATE DEFINER=`user`#`192.168.0.1` FUNCTION `FN_GET_USER_DETAILS(userID INT) RETURNS VARCHAR(25) CHARSET utf8
BEGIN
DECLARE user_getempcode VARCHAR(100);
SELECT DISTINCT(reg.empcode) INTO user_getempcode FROM m_registration_seq_num AS reg
INNER JOIN EMP_SECRET_CODE ecd
ON reg.tempcd = ecd.secretcd AND reg.lang_cd = ecd.lang_cd
RETURN user_getempcode;
END$$
DELIMITER ;
Can anyone has idea of what I am missing here.
I think you are missing AS before alias name of table EMP_SECRET_CODE . it should be like this:
CREATE DEFINER=`user`#`192.168.0.1` FUNCTION `FN_GET_USER_DETAILS(userID INT) RETURNS VARCHAR(25) CHARSET utf8
BEGIN
DECLARE user_getempcode VARCHAR(100);
SELECT DISTINCT(reg.empcode) INTO user_getempcode FROM m_registration_seq_num AS reg
INNER JOIN EMP_SECRET_CODE AS ecd
ON reg.tempcd = ecd.secretcd AND reg.lang_cd = ecd.lang_cd
RETURN user_getempcode;
END$$

call simple database procedure using Slick 3.0

I have written a simple database procedure in mySQL as follows:
DROP PROCEDURE IF EXISTS sp_doSomething;
DELIMITER //
CREATE PROCEDURE sp_doSomething
(IN pVal1 varchar(100),
IN pVal2 int(15)
)
BEGIN
DECLARE vCnt int(5) DEFAULT 0;
DECLARE vID int(15) DEFAULT 0;
DECLARE vTempID int(15) DEFAULT 0;
-- get ID
SELECT id INTO vID FROM T1
WHERE name = pVal1;
-- get count
SELECT count(*) INTO vCnt FROM T1
WHERE owner = vID;
-- get the log
INSERT INTO log select CONCAT('-v1-:', pVal1, ':-v2-:', pVal2);
-- Create basic stuff if it doesn't exist
IF vFolderCnt = 0 THEN
INSERT INTO T1 (`id`, `col1`, `col2`, `col3`)
SELECT null, vID, 'some value', CONCAT(vID,'^1') FROM T1
WHERE owner = 0;
END IF;
commit;
END //
DELIMITER ;
Now, I want to call this procedure in my Play Framework 2.4 application which uses Slick 3.0. It is such a simple thing but I am really struggling with it as there is no proper documentation available. It's very frustrating.
As it's mentioned on Google Group here https://groups.google.com/forum/#!searchin/scalaquery/procedure/scalaquery/BUB2-ryR0bY/EFZGX663tRYJ
I tried calling the procedure by different way. The code compiles but the procedure does not get called at all.
This statement gives an action error.
db.run(sql"{call sp_doSomething('${st.val1}', 1)}")
The following statement compiles fine but does not invoke the procedure.
db.run(sql"{call sp_doSomething('${st.val1}', 1)}".as[Int])
The following statement compiles fine but does not invoke the procedure.
db.run(sqlu"{call sp_doSomething('${st.val1}', 1)}")
Or
db.run(sqlu"{?=call sp_doSomething('${st.val1}', 1)}")
I have granted the Execute permission on the procedure to my DB user and verified it.
Also, I am not sure, whether the COMMIT is required in the procedure or not?
Any help, will be highly appreciated.
I have managed to invoke the stored procedure using old prepareCall method. Here's how I have done it. Hope, it might help someone.
db.withSession {
implicit session => {
val cs = session.conn.prepareCall("{call sp_doSomething(?, ?)}")
cs.setString(1, st.val1)
cs.setLong(2, 1L)
val result = cs.executeUpdate()
}
}
But I would be still interested in invoking the procedure using sql"" or sqlu"".
For me the following works in Slick 3.2:
delimiter //
create procedure Try1()
begin
select userid from TBL_USER where id = "4";
end //
delimiter ;
Then
def runProcByRawSql() : Future[Vector[String]] = {
def runproc = sql"""call Try1()""".as[String]
db.run(runproc)
}

MySQL - use result of nested stored procedure

Is there any way to use the return value of a stored procedure in another stored procedure?
Just a very basic theoretical example:
CREATE PROCEDURE `user_read_name_and_email` (
IN `param_user_id` INT
)
BEGIN
DECLARE `current_user` SET;
SET `current_user` = CALL `user_read`(`param_user_id`);
SELECT `user_name`, `user_email` FROM `current_user`;
END
CREATE PROCEDURE `user_read` (
IN `param_user_id` INT
)
BEGIN
SELECT * FROM `user` WHERE `user_id` = `param_user_id`;
END
I think the one and only workaround is to use temporary tables.
Your example would be possible in MS SQL Server 2008 - there you can assing output of stored procedure to some variable.

Weird issue with a stored procedure in MySQL

I need to add a new stored procedure on our company's MySQL server. Since it's just slightly different, I used an already existing one, added the additional field and changed the name of the procedure. The weird thing now is that when I want to execute the statement, it returns:
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 3
reffering to the 0 in this line: SET #update_id := 0; What makes it weird is, that I queried that stored procedure by using SHOW CREATE PROCEDURE . It's saved in our database and is working fine. I just can't use it as a new stored procedure (no matter if I try to apply it to the new test database or if I use it on the existing database by giving it a new name).
I searched the internet for a solution. Unfortunately to no avail. I even set up a new database with a new table and some demo values where I tried to execute the original, unaltered stored procedure. It returns the exact same error.
Here's the currently used and working stored procedure I'm talking about:
CREATE DEFINER=`root`#`localhost` PROCEDURE `customer_getcard`(IN Iinstance INT, IN Itimebuy DOUBLE, IN Iprice DECIMAL(10,2), IN Itariff INT, IN Icomment VARCHAR(128))
BEGIN
SET #update_id := 0;
UPDATE customer_shop SET state = 1, id = (SELECT #update_id := id), instance=Iinstance, timebuy=Itimebuy, price=Iprice, comment=Icomment WHERE tariff=Itariff AND state = 0 LIMIT 1;
SELECT * FROM customer_shop WHERE id = #update_id;
END
I hope you guys can help me as I am completely out of ideas what's wrong. :/
Regards, Mark
You need to define an alternative command delimiter, as MySQL currently thinks your CREATE PROCEDURE command ends at the first ; it encounters (on line 3, after the 0), which would be a syntax error as it's after a BEGIN but before the corresponding END:
DELIMITER ;; -- or anything else you like
CREATE PROCEDURE
...
END;; -- use the new delimiter you chose above here
DELIMITER ; -- reset to normal
MySQL stored procedures do not use ":=" for value assignment, just use "=".
Also don't think "id = (SELECT #update_id := id)" is acceptable. Here's an alternative solution (untested):
CREATE DEFINER=`root`#`localhost` PROCEDURE `customer_getcard`(IN Iinstance INT, IN Itimebuy DOUBLE, IN Iprice DECIMAL(10,2), IN Itariff INT, IN Icomment VARCHAR(128))
BEGIN
select id into #update_id from customer_shop WHERE tariff=Itariff AND state = 0 LIMIT 1;
UPDATE customer_shop SET state = 1, instance=Iinstance, timebuy=Itimebuy, price=Iprice, comment=Icomment where id = #update_id;
SELECT * FROM customer_shop WHERE id = #update_id;
END
You may also want to put error handlers in case there's no matching row to be edited.