Trying to learn MySQL and transactions - mysql

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.

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

I am writing a stored procedure on MYSQL to check if there are recording matching some criteria and output values.
I am used to write in MSSQLSEVER
here is an excerpt of the procedure:
CREATE PROCEDURE prc1(
IN input VARCHAR(15),
OUT output INT
)
this_proc:
BEGIN
SET output = 0;
DECLARE inputCount INT DEFAULT 0;
SELECT COUNT(name) INTO inputCount FROM table WHERE table.name = input;
IF (inputCount> 0) THEN
SET output= 1;
LEAVE this_proc;
END IF;
END;
i am getting errors at each one of this lines:
SET output = 0;
DECLARE ...
IF ...
END IF;
END;
am i doing any syntax error or something?
Give this a shot. It gets past syntax errors, cleans up labels, points you toward fixing mytablename, wraps with delimiters, shows call.
drop procedure if exists prc1;
DELIMITER $$
CREATE PROCEDURE prc1(
IN input VARCHAR(15),
OUT output INT
)
-- this_proc:
BEGIN
DECLARE inputCount INT;
set input=0;
SET output = 0;
SELECT COUNT(name) INTO inputCount FROM mytablename WHERE name = input; -- fix mytablename
IF (inputCount> 0) THEN
SET output= 1;
-- LEAVE this_proc; -- not necessary, you are about to leave anyway !
END IF;
END;
$$ -- signify end of block
DELIMITER ; -- reset to default delimiter
Test it
call prc1('fred',#myVar);
Delimiters
Delimiters are important to wrap the block of the stored proc creation. The reason is so that mysql understands that the sequence of statements that follow are still part of the stored proc until it reaches the specified delimiter. In the case above, I made up one called $$ that is different from the default delimiter of a semi-colon that we are all used to. This way, when a semi-colon is encountered inside the stored proc during creation, the db engine will just consider it as one the many statements inside of it instead of terminating the stored proc creation. Without doing this delimiter wrapping, one can waste hours trying to create their first stored proc getting Error 1064 Syntax errors. At the end of the create block I merely have a line
$$
which tell mysql that that is the end of my creation block, and then the default delimiter of a semi-colon is set back with the call to
DELIMITER ;
Mysql manual page Using Delimiters with MySqlScript. Not a great manual page imo, but trust me on this one. Same issue when creating Triggers and Events.

Syntax error MySql trigger: While_Sym

I'am developing a small project with PHP and MySql on a Wamp server. I just discovered the wonderful principle of SQL triggers. Hum... well. It would be wonderful if I could use it.
Indeed I have a problem with the following script:
BEGIN
SET #liste = NEW.reponse
WHILE LEN(#liste) > 0
BEGIN
IF PATINDEX('%,%',#liste) > 0
BEGIN
SET #choix = SUBSTRING(#liste, 0, PATINDEX('%,%', &liste))
INSERT INTO resultat (referendum, choix) VALUES (NEW.id, #choix)
SET #liste = SUBSTRING(#liste, LEN(#choix + ',') + 1, LEN(#liste))
END
END
END
I would like to execute this trigger after the insertion of a record in table "Referendum". In this table, there is a field "reponse" which contains the different possible answers. This field contains this kind of data: "Yes,No,I don't know". For each new question, I want to insert a new record in table "Resultat" per possible answer.
In my example, three new records: one for Yes, one for No and one for I don't know.
My code comes from an example on the internet but it doesn't work properly. SQL returns a syntax error with message "While_Sym expected"...
I tried to add semicolon following what I found on the internet but no way...
I guess you need something like this:
CREATE TRIGGER mytrigger AFTER INSERT
ON Referendum FOR EACH ROW
BEGIN
DECLARE cnt int;
DECLARE str varchar(100);
Set cnt = CHAR_LENGTH(NEW.reponse)
- CHAR_LENGTH(Replace(NEW.reponse,',','')) +1;
WHILE cnt > 0 DO
Set str = SUBSTRING_INDEX(
SUBSTRING_INDEX( New.reponse,',', -cnt)
,',',1);
INSERT INTO resultat (referendum, choix)
VALUES (NEW.id, str);
Set cnt = cnt - 1;
END WHILE;
END;
Demo: http://sqlfiddle.com/#!2/c7321/1
Some thoughts:
There are no PATINDEX nor LEN functions in MySql, they come from SQL Server.
Most functions are not standard in SQL, one shouldn't expect that something that works on database X should also work on database Y (and vice versa)
You always need to check the manual.
There is difference in MySql between #variable and variable - they are not the same (opposite to SQL Server where there is only one kind of variables --> #variable).
Please refer to documentation to learn about #user_definied_variables and local_variables
http://dev.mysql.com/doc/refman/5.7/en/user-variables.html
http://dev.mysql.com/doc/refman/5.7/en/declare-local-variable.html
Depending on your client software you may need to use also DELIMITER xx command, for example in mysql console client or MySql-Workbench you need something like this to create a trigger without syntax errors:
DELIMITER $$
CREATE TRIGGER mytrigger AFTER INSERT
ON Referend ......
......
......
END;
$$
DELIMITER ;

How do I handle errors in a basic MySQL stored procedure?

Let's say I have a stored procedure:
DELIMITER $$
CREATE DEFINER=`root`#`%` PROCEDURE `SetupBlocks`(
IN myBlock VARCHAR(20)
)
BEGIN
INSERT INTO blocks (block)
VALUE (myBlock);
END
What if I made a mistake in my code and DB setup, and the column block only allows for 15 characters but someone using my application has been able to get 20 characters into myBlock? I would get an error similar to this for this example:
Error Code: 1406. Data too long for column 'block'
Is there some way to handle any error (not just this one) and then report it into a table called BlockSprocErrors for monitoring within MySQL and within the stored procedure itself?
Just looking for a very basic example by modifying my procedure above.
Here is what I ended up doing:
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS condition 1
#SQLState = RETURNED_SQLSTATE, #SQLMessage = MESSAGE_TEXT;
SELECT CONCAT('Database error occurred, state - ',#SQLState, '; error msg - ', #SQLMessage) INTO #errorString;
CALL Collectors_Errors
(#errorString,
'Collectors_InsertAlbum',
barcodeApp,
usernameApp);
END;

create procedure fails?

when trying to create a simple procedure in mysql 5.1.47-community it fails everytime i've tried everything!
even simple things like this!
DELIMITER //
CREATE PROCEDURE two ()
begin
SELECT 1+1;
end;
//
The error is
ERROR: 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 'mydb' at line 1
The error message you've given doesn't correspond to the code you've pasted. You're referring to "mydb" somewhere in the SQL you're running yet it's not anywhere in the code you've put in the question.
The code you've given should work fine as I see no syntax errors, you may just need to give it a database to work on ("test" in my case here, perhaps it should be "mydb" for you?).
DELIMITER //
CREATE PROCEDURE test.two ()
begin
SELECT 1+1;
end;
//
DELIMITER ;
CALL test.two;
However, I suspect the error you're getting is become of a line in your SQL that you're not showing us.
EDIT
It could perhaps be the delimiter command. You're changing the delimiter to // rather than the default ;. So perhaps you've run that command (and changed the delimiter for your session to //), and then tried to run USE mydb; where the ; is no longer recognised as a valid delimiter for your session, and that could be giving you the error. Try putting delimiter ; before your use line and see if that helps (and then use it again after you've defined your stored procedure so you can call it). This is just a theory though, as I'm not sure of the intricacies of the delimiter command.
Remove the final delimiter "end" instead "end;"
I had the same problem using heidisql as the fronted to enter the SQL. My first attempt was:
CREATE PROCEDURE Add_Two (IN someNumber int, OUT result INT)
BEGIN
SELECT someNumber +2 INTO result;
END
and this resulted in SQL ERROR (1064) because i was not aware that when using a client program a delimiter is needed to define the stored procedures.
After changing the above to this:
DELIMITER //
CREATE PROCEDURE Add_Two(IN someNumber int, OUT result INT)
BEGIN
SELECT someNumber +2 INTO result;
END
//
It worked out.
Example to call it
SET #someNumber :=8;
CALL Add_Two(#someNumber, #result);
SELECT #result;