MySQL - CREATE DEFINER syntax error - mysql

I am trying to update a stored function in our MySQL database. The update is to be released to multiple devices so I am doing it through an update.sql file.
Here is the function
DROP FUNCTION `STAFF_MPT`;
CREATE DEFINER=`jelena`#`%` FUNCTION `STAFF_MPT`(`par_stocktake_staff_id` INT) RETURNS DECIMAL(20,0) NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER BEGIN
DECLARE proc_total INT;
DECLARE proc_time INT;
SET proc_total = (SELECT SUM(quantity) FROM stocktake_scans WHERE stocktake_staff_id = par_stocktake_staff_id);
SET proc_time = (SELECT TIMESTAMPDIFF( SECOND , MIN( scan_date ) , MAX( scan_date ) ) AS area_time
FROM stocktake_scans
WHERE stocktake_staff_id = par_stocktake_staff_id
);
RETURN (proc_total/proc_time)*3600;
END
It was just reported to me by the test team that the report that uses this function did not generate properly. I tried to run the code in PMA SQL query window and got the following:
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
Can someone tell me what am I missing? According to this, line 3 is empty, so how could it possibly have a syntax error?

As of MySQL docs:
If you use the mysql client program to define a stored program containing semicolon characters, a problem arises. By default, mysql itself recognizes the semicolon as a statement delimiter, so you must redefine the delimiter temporarily to cause mysql to pass the entire stored program definition to the server.
To redefine the mysql delimiter, use the delimiter command.
#juergen_d hinted in the comment: you have to define your procedure with a delimiter:
DROP FUNCTION `STAFF_MPT`;
delimiter ||
CREATE DEFINER=`jelena`#`%` FUNCTION `STAFF_MPT`(`par_stocktake_staff_id` INT) RETURNS DECIMAL(20,0) NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER BEGIN
DECLARE proc_total INT;
DECLARE proc_time INT;
SET proc_total = (SELECT SUM(quantity) FROM stocktake_scans WHERE stocktake_staff_id = par_stocktake_staff_id);
SET proc_time = (SELECT TIMESTAMPDIFF( SECOND , MIN( scan_date ) , MAX( scan_date ) ) AS area_time
FROM stocktake_scans
WHERE stocktake_staff_id = par_stocktake_staff_id
);
RETURN (proc_total/proc_time)*3600;
END
||
delimiter ;

Related

MySQL Stored Procedure - increment a variable

Why is my stored procedure erroring on the last two lines. Am i missing something? I am trying to write something that takes my basis name and creates a variable that increments it by 1 and continues until it hits 150. I know how to do this in Microsft SQL which might be where my syntax errors are coming from. Thanks.
USE repo;
DELIMITER $$
Create DEFINER = 'root' # 'localhost' procedure csvOutput()
BEGIN DECLARE basis_name int; SET #basis_name = 0;
if basis_name < 150 then
set basis_name = basis_name + 1;
SELECT *
FROM
(SELECT
'cbt.component',
'fl.input_flow',
'ft.flow',
'Function_ID',
'sf.subfunction',
'fl.output_flow',
'ft2.flow',
'# of times it appears',
'sf.tier'
UNION ALL (SELECT
cbt.component,
fl.input_flow,
ft.flow,
sf.id AS 'Function ID',
sf.subfunction,
fl.output_flow,
ft2.flow,
COUNT(a.name) AS '# of times it appears',
sf.tier
FROM
artifact a, function fu, flow fl, flow_type ft, subfunction_type sf, flow_type ft2, comp_basis_type cbt
WHERE
a.id = fu.describes_artifact
AND fu.id = fl.describes_function
AND fl.input_flow = ft.id
AND fl.output_flow = ft2.id
AND fu.subfunction_type = sf.id
AND a.basis_name = 115
AND fu.supporting = 0
AND a.basis_name = cbt.id
AND sf.tier >= 3
GROUP BY fl.input_flow
ORDER BY COUNT(fu.id) DESC)) resulting_set INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 5.7/Uploads/test4.csv' FIELDS ENCLOSED BY '"' TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '';
END$$
Delimiter;
I tested your statement. For future reference, when you ask about an error on Stack Overflow, please include the error.
This is the error I got from testing:
ERROR 1064 (42000): 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 basis_name int; SET #basis_name = 0;
I see the problem, it's actually on this line:
USE repo; DELIMITER $$ Create DEFINER = 'root' # 'localhost' procedure csvOutput()
Keep in mind that DELIMITER sets the statement delimiter to all of the following text until end of line. So you have set the delimiter not to $$, but to the entire string: $$ Create DEFINER = 'root' # 'localhost' procedure csvOutput()
The error reports some problem with DECLARE because it's trying to start a new statement, not part of the procedure. BEGIN TRANSACTION is a legal statement, but other than that, BEGIN cannot be used on its own in MySQL. So BEGIN DECLARE... caused MySQL to say, "whoah, that's not what I expect you to add after BEGIN!"
Just add a newline after DELIMITER $$
Also note that you must not use a semicolon after the DELIMITER statement because that will become part of your statement terminator too. How else could you set the delimiter back to ;?
Another issue that would help you in the future, but it is not the root cause of the error you asked about:
In MySQL, basis_name and #basis_name are two different variables.
Variables declared with DECLARE within a procedure don't have the # prefix. You use them without the prefix when you declare them and when you use them. These variables are local to the stored procedure where they are declared.
Variables with the # prefix don't need to be declared. These are called "user-defined variables". You can create them merely by assigning a value to an identifier. You must always use the # prefix when you reference these variables. These variables are not local to the procedure where you set them. They retain their value in your current session after the procedure has finished. You can set their value and read their value with simple SQL statements outside a procedure.
This is a common issue on which Microsoft users get confused when moving to MySQL.

MySql syntax error on procedure parameter

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

Why my sql query not runing as I have set the right DELIMITER

DELIMITER $$
ALTER PROCEDURE GetUContent(IN CurPage INT,IN PageRows INT)
BEGIN
DECLARE #rownum INT DEFAULT 0;
SELECT #rownum:=#rownum+1 as T_ROWID,
tcl.T_ID AS T_CID ,
tcl.T_CONTENTS ,
tcl.T_TYPE ,
tcl.T_STATUS ,
tcl.T_GOAL ,
tcl.T_IMGURL AS T_CIMGURL ,
tcl.T_CREATETIME ,
tul.T_ID AS T_UID ,
tul.T_NAME ,
tul.T_IMGURL AS T_UIMGURL ,
IFNULL(trl.T_RCOUNT, 0) AS T_RCOUNT
FROM T_CONTENT tcl LEFT JOIN
( SELECT T_CID , COUNT(T_ID) AS T_RCOUNT
FROM T_REPLAY WHERE T_STATUS = 1 GROUP BY T_CID
) trl ON tcl.T_ID = trl.T_CID
INNER JOIN T_USERINFO tul ON tcl.T_UID = tul.T_ID
WHERE tcl.T_STATUS = 1
ORDER BY tcl.T_CREATETIME LIMIT PageRows*CurPage,PageRows;
END $$
DELIMITER ;
Error Info:
ERROR 1064 (42000) at line 2 in file: '/root/git/Thinking/src/main/resources/dataScript.sql': 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 'CurPage INT,IN PageRows INT)
BEGIN
DECLARE #rownum INT DEFAULT 0;
SELECT ' at line 1
Must Infomation:
I use the default mysql client
Runing Command: . /root/git/Thinking/src/main/resources/dataScript.sql
The content of dataScipt.sql is the upper coding.
I think you need to use
DECLARE rownum INT DEFAULT 0;
SELECT rownum=rownum+1 as T_ROWID,
...
because #... variables are session variables that cannot be used with DECLARE.
EDIT
And ALTER PROCEDURE does not support changing the method body in MariaDB:
However, you cannot change the parameters or body of a stored
procedure using this statement; to make such changes, you must drop
and re-create the procedure using DROP PROCEDURE and CREATE PROCEDURE.

parameters sql query inside of a stored procedure mysql

I'm working with stored procedures in mysql, so I have the following procedure:
DELIMITER ##
DROP PROCEDURE IF EXISTS generarEstadisticoRD ##
CREATE PROCEDURE generarEstadisticoRD ( mesInicial INT,anualInicial INT, mesFinal INT,anualFinal INT, codigoEntidad CHAR(3),mes INT )
BEGIN
DECLARE controlador INT;
DECLARE tipoDocumento CHAR(2);
DECLARE cursorDocumentos CURSOR FOR SELECT DISTINCT e.claseDocIdentidadFallecido
FROM EstadisticoRD e WHERE e.anual>=anualInicial AND e.anual<=anualFinal
AND e.mes >=mesInicial AND e.mes<=mesFinal AND e.codOficina=codigoEntidad;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET controlador = 1;
DROP TEMPORARY TABLE IF EXISTS estadistico;
CREATE TEMPORARY TABLE IF NOT EXISTS
estadistico( TIPO CHAR(2), MES INT );
OPEN cursorDocumentos;
cursorLoop : LOOP
FETCH cursorDocumentos INTO tipoDocumento;
IF( controlador=1 ) THEN
LEAVE cursorLoop;
END IF
/**
*Lógica
*/
INSERT INTO estadistico(`TIPO`,`MES`)
SELECT DISTINCT
c.descripcion,
IFNULL( (SELECT e.numRegistrosReportados FROM estadisticoRD e WHERE e.codOficina=codigoEntidad
AND e.claseDocIdentidadFallecido=tipoDocumento AND e.mes=mes ), 0)
FROM estadisticoRD e, claseDoc c WHERE e.codOficina=codigoEntidad AND e.claseDocIdentidadFallecido=tipoDocumento
AND c.claseDoc = e.claseDocIdentidadFallecido;
END LOOP cursorLoop;
CLOSE cursorDocumentos;
SELECT * FROM estadistico;
END ##
DELIMITER ;
I get the following messages when I try to execute the procedure:
Executed successfully in 0,001 s, 0 rows affected.
Line 2, column 1
Error code 1064, SQL state 42000: 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 estadistico(`TIPO`,`MES`)
SELECT DISTINCT c.descripcion,
' at line 24
Line 3, column 1
So, what am I doing wrong?.
UPDATE 1:
The I corrected the mistake with semicolon thanks #Daniel Victoria
But now I get the following mistake:
Error code 1267, SQL state HY000: Illegal mix of collations (latin1_spanish_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '='
Exactly I get this mistake when I do
SELECT DISTINCT e.claseDocIdentidadFallecido
FROM EstadisticoRD e WHERE ... AND e.codOficina=codigoEntidad;
why when I do e.codOficina=codigoEntidad I get this mistake, how to fixed it?.
UPDATE 2:
To solve it, I need to put COLLATE latin1_swedish_ci after to the column that has the mistake.
In this case the new query is :
SELECT DISTINCT *
FROM estadisticoRD e WHERE e.anual>=anualInicial AND e.anual<=anualFinal
AND e.mes >=mesInicial AND e.mes<=mesFinal AND e.codOficina = codigoEntidad COLLATE latin1_swedish_ci;
I hope to finish this procedure the best way.
Your are missing a semicolon (;) after the "END IF"

Assign In SELECT Command for MySQL Not working

I am trying to assign the #lastupd variable. as in below line:
select #lastupd := max(`last_edited_time`)
from flyspray_comments where task_id = taskID;
But mysql give me error:
ERROR 1064 (42000): 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
set #lastupd = 0; select #lastupd := max(last_edited_time) from
flys' at line 2
The code:
delimiter $$
use flyspray $$
CREATE function last_upd_time(taskID INT)
BEGIN
set #lastupd = 0;
select #lastupd := max(`last_edited_time`) from flyspray_comments where task_id = taskID;
RETURN #lastupd;
END
$$
delimiter ;
Your immediate error has nothing to do with assignment. It is caused by the invalid definition of the function. You're missing mandatory RETURNS clause which indicates the return type of the function. See CREATE FUNCTION Syntax.
There is no need to use a variable in your case, less a user(session) variable. Just RETURN the result of the query.
And since you may use the only statement there is no need in a BEGIN ... END block and changing DELIMITER
That being said a streamlined and working version of your function may look like
CREATE FUNCTION last_upd_time(_task_id INT)
RETURNS DATETIME -- mandatory clause
RETURN -- just return the result of the query
(
SELECT MAX(last_edited_time)
FROM flyspray_comments
WHERE task_id = _task_id
); -- use default delimiter since it's a one-statement function
Here is SQLFiddle demo
Now, if you'd like to use a variable for some reason then
use a local instead of user(session) one.
assign a value with either SET or SELECT ... INTO syntax.
It may look like
DECLARE lastupd DATETIME DEFAULT NULL; -- or 0
SET lastupd =
(
SELECT MAX(last_edited_time)
FROM flyspray_comments
WHERE task_id = _task_id
);
or
DECLARE lastupd DATETIME DEFAULT NULL; -- 0
SELECT MAX(last_edited_time)
INTO lastupd
FROM flyspray_comments
WHERE task_id = _task_id;