MySQL - Storing variables inside CREATE FUNCTION - mysql

I'm trying to figure out how to store variables inside a function in mySQL. I am trying to create a function that capitalizes a field name. Creating a function works if I don't create variables. The problem is this is difficult to read, and is easy to make mistakes with.
CREATE FUNCTION capitalize(string TEXT)
RETURNS TEXT
RETURN CONCAT(UPPER(LEFT(string,1)), LOWER(RIGHT(string, LENGTH(string) - 1)));
When I try to add variables using the DECLARE and SET keywords, it no longer works.
CREATE FUNCTION capitalize(string TEXT)
RETURNS TEXT
DECLARE first_letter TEXT;
DECLARE last_letters TEXT;
SET first_letter = UPPER(LEFT(string,1));
SET last_letters = LOWER(RIGHT(string, LENGTH(string) - 1));
RETURN CONCAT(first_letter, last_letters);
I get this error message
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 4
I've fiddled around with it, removing semicolons, and double/triple checking parentheses. I've fiddled with BEGIN and END statements but nothing seems to work at all.
I have searched extensively on this topic but cannot figure out where the problem lies.

The body of a CREATE FUNCTION can consist of only a single statement, which is why the first version works and the second doesn't. Fortunately, that single statement can be a compound statement enclosed in a BEGIN ... END block.
You need to enclose the function body in a BEGIN ... END block to allow MySQL to see it as a single statement; you'll also perhaps need to precede and follow it with DELIMITER statements (depending on your client, as Mr. Berkowski points out):
DELIMITER //
CREATE FUNCTION capitalize(string TEXT)
RETURNS TEXT
BEGIN
DECLARE first_letter TEXT;
DECLARE last_letters TEXT;
SET first_letter = UPPER(LEFT(string,1));
SET last_letters = LOWER(RIGHT(string, LENGTH(string) - 1));
RETURN CONCAT(first_letter, last_letters);
END; //
DELIMITER ;
(Note especially the space between the last DELIMITER and the semicolon.)

Related

MySQL Cursors - having errors in MySQL Workbench

I am trying to write a mysql program, which has cursors in it. Due to an error in writing an DECLARE query, MySQL Workbench is always showing me the DECLARE is not valid at this position, expected EOF, ALTER, ANALYZE, BEGIN, BINLOG, CACHE, ...
Could you help me solve this problem?
Here is my code:
DELIMITER //
BEGIN
declare Naslov_knjige VARCHAR(24);
declare Cena_knjige DECIMAL(8,2);
DECLARE cursor_cene CURSOR
FOR SELECT
Naslov,
Cena
FROM
prvi_test_v2.knjige;
OPEN cursor_cene //
FETCH NEXT FROM cursor_cene INTO
#Naslov_knjige,
#Cena_knjige //
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #Naslov_knjige + CAST(#Cena_knjige AS VARCHAR) //
FETCH NEXT FROM cursor_cene INTO
#Naslov_knjige,
#Cena_knjige //
END //
CLOSE cursor_cene //
DEALLOCATE cursor_cene //
END //
DELIMITER ;
Thanks for your help!
I will assume you omitted a line for CREATE PROCEDURE, because in MySQL a BEGIN...END block must be part of a stored routine. See https://dev.mysql.com/doc/refman/8.0/en/begin-end.html
BEGIN ... END syntax is used for writing compound statements, which can appear within stored programs (stored procedures and functions, triggers, and events).
You changed the DELIMITER:
DELIMITER //
Using this delimiter terminates the whole CREATE PROCEDURE statement. You should not do this after the first statement in the body of the procedure. You need to use the normal ; terminators for each statement within the body of the procedure. The reason for changing the delimiter is so you can use ; for each statement in the procedure without ending the CREATE PROCEDURE.
See examples and documentation here: https://dev.mysql.com/doc/refman/8.0/en/stored-programs-defining.html
That's the reason for the error you got. You used // to terminate OPEN cursor_cene // which ended the CREATE PROCEDURE, but clearly there was more to that procedure.
There are other problems with your procedure. You seem to be using Microsoft SQL Server syntax, but MySQL is different.
Naslov_knjige is not the same variable as #Naslov_knjige in MySQL. Don't use the # sigil in front of local variables. If you use the # sigil, this refers to a user-defined variable.
The WHILE ##FETCH_STATUS = 0 syntax is specific to Microsoft SQL Server. MySQL has different syntax for running a cursor loop. See example in the documentation: https://dev.mysql.com/doc/refman/8.0/en/cursors.html
That's as far as I got. There may be more problems, but I am not going to look for them.

MySQL Stored Procedure - if then not functioning

I'm converting SQL Server stored procedures to MySQL and running into issues. I have a stored procedure with an IF THEN ELSE that, while not giving errors, is not returning any data either and I'm not seeing the problem to fix it. The queries by themselves are correct and return data but don't seem to work in the stored procedure. This is a simplified version of the real query just FYI.
The SQL for creating the stored procedure is:
DROP PROCEDURE IF EXISTS `sp_GetVolunteerAwardsList`;
DELIMITER //
CREATE PROCEDURE `sp_GetVolunteerList`( IN glAward_in int)
BEGIN
DECLARE glAward_In INT;
DECLARE awardType_In varchar(100);
DECLARE awardActive INT;
IF (glAward_In) = 0 THEN
SELECT * FROM tbl_volunteer
ELSEIF (glAward_In) = 1 THEN
SELECT * FROM tbl_volunteerpositions
END IF;
END
//
As always, any assistance would be most appreciated.
Check the glAward_In parameter or variable.
The SP is receiving the parameter glAward_in, i in lower case.
Then there is a DECLARE that declares a different variable glAward_In, i in upper case.
The if is done using the glAward_In in uppercase which is not set in any place of the SP. And the parameter in lower case is not used anywhere in the SP.
I think you have to remove the DECLARATION of the variable in upper case, and use the parameter in lowercase for the IF evaluation.

Error 1064 declaring variable inside trigger

I'm having trouble declaring a variable inside a trigger.
SET DELIMITER ;;
BEGIN
DECLARE qtyNow INT;
SET qtyNow = (
SELECT qty
FROM warehouse
WHERE bin_id = 'GA66'
);
DECLARE need INT;
SET need = (
SELECT min_level
FROM warehouse
WHERE bin_id = 'GA66'
);
END;;
SET DELIMITER ;
I get error #1064 which means illegal syntax. I don't see where I went wrong. I even removed all that bulk and just had
DECLARE qtyNow INT;
And this single line still pops the error.
I see two problems.
One, you have a BEGIN...END block but you are not declaring a trigger.
https://dev.mysql.com/doc/refman/5.7/en/begin-end.html says:
BEGIN ... END syntax is used for writing compound statements, which can appear within stored programs (stored procedures and functions, triggers, and events).
You can't use BEGIN...END as a bare statement. It must be part of a CREATE TRIGGER, CREATE PROCEDURE, CREATE FUNCTION, or CREATE EVENT.
Two, you have two DECLARE statements in your block, with a SET in between.
https://dev.mysql.com/doc/refman/5.7/en/declare.html says:
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements.
You are trying to use a second DECLARE after you have done another statement, SET. Do all your DECLAREs up front.

Why does this function have a syntax error near DECLARE?

The code is:
DELIMITER $$
CREATE FUNCTION CHECK_AVABILITY(nama CHAR(30))
RETURNS INT(4)
DECLARE vreturn INT(4);
BEGIN
IF nama = 'ika' THEN
SET vreturn = 0;
ELSE
SET vreturn = 1;
END IF
RETURN vreturn;
END $$
The error message is:
ERROR 1064 (42000): You Have an error inyour sql syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DECLARE vreturn INT4); BEGIN'
Help is appreciated.
Move DECLARE vreturn INT(4) inside the BEGIN / END block. You probably also need a ; after the END IF.
Additionally, this looks like it is to be a DETERMINISTIC function. Add the DETERMINISTIC keyword before the BEGIN.
DELIMITER $$
CREATE FUNCTION CHECK_AVABILITY(nama CHAR(30))
RETURNS INT(4)
DETERMINISTIC
BEGIN
DECLARE vreturn INT(4);
IF nama = 'ika' THEN
SET vreturn = 0;
ELSE
SET vreturn = 1;
END IF;
RETURN vreturn;
END $$
Here's my findings on the subject:
This is a quote from a manual:
"You need a BEGIN/END block when you have more than one statement in the procedure. You use the block to enclose multiple statements.
But that's not all. The BEGIN/END block, also called a compound statement, is the place where you can define variables and flow of control."
In other words:
(These rules appear to apply to triggers and stored procedures in the same way, as it seems the same syntax is used in both.)
First, notice that a flow control group of keywords such as IF ... END IF or WHILE ... END WHILE is seen as a single statement as far as its termination with a semicolon is concerned, that is, it is terminated as a whole by a single semicolon at the end of it: IF ... END IF; WHILE ... END WHILE;.
Then, if the body of a trigger or stored procedure contains just one stament, and that statement is not a variable declaration nor a flow control group of keywords as above, that statement may not be terminated by a semicolon (;) and not enclosed by a BEGIN ... END block.
On the contrary, if the body of a trigger or stored procedure contains more than one stament, and particularly if it contains variable declarations and/or flow control groups of keywords, then it must be enclosed in a BEGIN ... END block.
Finally, the BEGIN ... END block itself must not be terminated by a semicolon.
Hope this helps.

Trying to learn MySQL and transactions

Over the last couple of days I have tried to write an Stored procedure in MySQL and I have some truble getting it to work. Hope someone here can give me some input :)
The example I post is for asp.Net Membership provider to create a new user. I expect to send email and password to the DB and get an int return to verify that the userdeatils was written to the DB.
I use a MySQL DB 5.1 (I think) and write the SQL to a webinterface.
I got 2 sidequestions, can someone explain that too :):
1) I use a DELIMITER, but do not know what it does.
2) I am not sure if I have to do other things then to set autocommit = 0 to get transactions to work, or if I even have to do that.
I know that I could have used a IF / ELSE statement instead of a transaction, but would like to do it with one to find out how it works. (I expect to use it alot later)
The code I can not get to work:
DELIMITER //
CREATE DEFINER=`websharp_dk`#`%` PROCEDURE `CreateUser`(
IN _username VARCHAR(100),
IN _Password VARCHAR(100))
RETURNS INT
BEGIN
SET autocommit = 0;
DECLARE return_value INT;
BEGIN TRY
START TRANSACTION
INSERT INTO User
(Email
,Password
,Failed_Password_Count
,Creation_Date)
VALUES
(_username
,_Password
,0
,Datetime.Now())
SET return_value = 1;
COMMIT;
END TRY
BEGIN CATCH
ROLLBACK
SET return_value = 0;
END CATCH
BEGIN FINALLY
RETURN return_value;
END FINALLY
END//
DELIMITER ;
Edit:
The error message I get is:
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 'INT BEGIN SET autocommit = 0; DECLARE return_value INT; ' at line 4
To get support for transactions, make sure you are using the InnoDB storage engine rather than the default MyISAM.
As far as that code itself, my first question would be, why are you wrapping that single query in a transaction? Also, what errors are you seeing?
The delimiter redefines what sequence of characters you use to end an sql statement. The entire create procedure is one big statement and you need to tell MySQL where it ends with something (would normally be ';'). But since you have a bunch of other statements in the "body" (between BEGIN and END) of the create procedure statement that all need to be ended too you need to redefine the delimiter so you don't end the create procedure statement at the first ';'.
Without redefining the delimiter, MySQL would think that the create procedure statement looked like this and then begin a new statement:
CREATE DEFINER=`websharp_dk`#`%` PROCEDURE `CreateUser`(
IN _username VARCHAR(100),
IN _Password VARCHAR(100))
RETURNS INT
BEGIN
SET autocommit = 0;
Using DELIMITER ; at the end of the script changes the delimiter back to ';' and is not needed although it's good practice to do so.