Does this function conform to ANSI SQL standard? - mysql

I was wondering if anyone can tell me if this function follows ANSI SQL standard, and for future reference are there any resources that i can use to find if my SQL conforms to ANSI standards. And the DBMS i am using is MySQL.
CREATE FUNCTION INCREMENT()
RETURNS INT
BEGIN
DECLARE oldVal INT;
DECLARE newVal INT;
SELECT currentVal INTO oldVal FROM atable FOR UPDATE;
SET newVal=oldVal +1;
UPDATE atable SET currentVal=newVal;
RETURN newVal;
END;

Found a validation tool that can check if your SQL conforms to SQL 2003.
http://developer.mimer.com/validator/parser200x/index.tml

Based on this comment
basically i need to retrieve the new updated value if i do UPDATE
table SET current = current + 1 and then perform a select to get the
new value, this could cause issues as what if another transaction
updates between the update and select.
I don't think your problem has anything at all to do with SQL standards. I think your problem has to do with transactions and with transaction isolation levels.

Related

Defining user variables in stored procedures / routines for MySQL 9.0

According to the MySQL 8.0 deprecations notes, starting MySQL 9.0 the definition of user variables with DECLARE (e.g. DECLARE studentID INT) will be deprecated:
Support for setting user variables in statements other than SET was
deprecated in MySQL 8.0.13. This functionality is subject to removal
in MySQL 9.0.
Already nowadays MySQL 8.0.25 raises a warning:
1287 Setting user variables within expressions is deprecated and will
be removed in a future release. Consider alternatives: SET variable=expression, ..., or SELECT expression(s) INTO variables(s).
Therefore, I would like to understand how to properly replace DECLARE with SET. Let say, I have the following variables declared:
DECLARE cursor_studentID INT;
DECLARE done INT DEFAULT FALSE;
DECLARE cursor_i CURSOR FOR SELECT courseID FROM tblCoursesToCopy;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
And now I want to make these declaration MySQL 9.0 compatible. In case of DECLARE cursor_studentID INT; everything is relatively obvious:
DECLARE cursor_studentID INT; → SET #cursor_studentID;
The real obstacle is the last one case:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
How to replace it with SET-based approach?
The deprecation warnings are not clear, and are easily misunderstood.
The DECLARE syntax is not deprecated. I think the authors of the release notes do not consider that a method of "setting" a variable. Admittedly, it does set an initial value for a declared variable, by using the optional DEFAULT clause. But I still interpret it as a statement that is not counted as one that is deprecated.
What is deprecated is setting variables as a "side-effects" in expressions like this:
SELECT #row := #row+1, ...
That technique was a common workaround for MySQL's lack of window functions in releases before 8.0. But it's nonstandard syntax and is generally error-prone and tricky to use. Now that MySQL supports standard SQL window functions and common table expressions, you can write queries much like you would write in other popular implementations of SQL. The above example would be:
SELECT ROW_NUMBER() OVER (), ...
The other use of := assignments was to save expressions from a query's select-list into a user-defined variable. MySQL provides the SELECT ... INTO syntax for this usage. This has been supported for a long time, before version 8.0.
We have not heard any announcement of a change to the DECLARE syntax. That does not need to change.
Re your comments:
Instead of SELECT #myVar := somevalue ..., you can use either of the following forms:
SELECT someValue INTO #myVar ...
SET #myVar = (SELECT someValue FROM ...);
Note the latter form does not allow you to set more than one variable per query. The former allows you to set multiple variables like this:
SELECT someValue, otherValue INTO #myVar1, #myVal2 ...
Read the documentation on SELECT ... INTO that I linked to above.

Transactions within MySql Stored Procedures

I am trying to use a transaction within a MySQL Stored Procedure.
Specifically, update a user table with amended data from a temporary record. from another table.
then once transferred, delete the temporary record.
I have created the code below, which when executed returns the string "transaction has succeeded".
However, nothing is actually updated and the temporary record is Not deleted.
Both SQL statements, when executed separately work Just fine, the first one does the update, the second does the delete.
Can anyone enlighten me as to what may be wrong?
BEGIN
-- set a default response
DECLARE response varchar(48) DEFAULT "the transaction has failed.";
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
-- set vars
SET response = "the transaction has failed, you may have already updated the account.";
select response;
END;
START TRANSACTION;
-- we are inserting data, using information from another table
update user, updateUserNamesAndNumbers
SET user.firstName = updateUserNamesAndNumbers.firstName,
user.lastName = updateUserNamesAndNumbers.lastName,
user.landline = updateUserNamesAndNumbers.landline,
user.mobile = updateUserNamesAndNumbers.mobile
WHERE
updateUserNamesAndNumbers.uuid = transferCode
AND
updateUserNamesAndNumbers.userId= user.user_id
;
-- finally delete the original tuple
DELETE from updateUserNamesAndNumbers
where uuid= transferCode ;
SET response="The transaction has succeeded";
COMMIT;
SELECT response;
END
Change the implicit join to an explicit join
update user join updateUserNamesAndNumbers on updateUserNamesAndNumbers.uuid = transferCode
I've Partially answered my own Question.
Thanks to P.Salmon, for Querying the transferCode variable.
It turns out I had defined the string as varchar(24), but the input was actually bigger than that.
So once I sorted that, the code worked, but only the first time.
I still need to have a really good think about this, as a second call to the same routine with the same transferCode input, where the temporary tuple had already been deleted by the first call, does not throw the MySQL Exception, as I thought it should. So "its Still Thinking Cap On Time"

MySQL Function Characteristic

I want to create a function that basically returns a random string. I don't know what characteristics to assign in this situation. I'm also in an environment that uses binary logging.
Here's a simplified version of my function:
CREATE FUNCTION `MYRAND`() RETURNS char(10) NOT DETERMINISTIC
RETURN CONCAT('rand_', FLOOR(RAND() * 10000));
I get this error when creating the function in my environment.
This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in
its declaration and binary logging is enabled (you might want to use
the less safe log_bin_trust_function_creators variable)
Possible characteristics:
NOT DETERMINISTIC - used because this function returns random values
READS/MODIFIES SQL DATA - Function does not read data from tables
NO SQL - I am calling other SQL functions (RAND) so I'm not sure if I should be specifying this or not...
Any advice on how to properly define this function when binary logging is enabled would be appreciated.
MySQL wants you to declare the function as DETERMINISTIC, NO SQL, or READS SQL DATA.
Is it DETERMINISTIC? No - Since it is random.
Does id read SQL DATA? No - Since you have no SELECT statement.
Does it modify SQL DATA? No - Since you have no INSERT, UPDATE or DELETE statement.
Since your function does not touch any data in the DB it's NO SQL.
So you should declare it as NOT DETERMINISTIC and NO SQL
CREATE FUNCTION `MYRAND`() RETURNS char(10) NOT DETERMINISTIC NO SQL
RETURN CONCAT('rand_', FLOOR(RAND() * 10000));
Use somthing like this code:
CREATE FUNCTION get_string(in_strlen int) RETURNS VARCHAR(500) DETERMINISTIC
BEGIN
set #var:='';
while(in_strlen>0) do
set #var:=concat(#var,IFNULL(ELT(1+FLOOR(RAND() * 1000),1,2,3,4,5,6,7,8,9));
set in_strlen:=in_strlen-1;
end while;
RETURN #var;
END

EXCEPTION WHEN OTHERS equivalent in MySQL

I am trying to port an Oracle trigger to MySQL. There's an EXCEPTION WHEN OTHERS statement in the trigger and while I have found equivalent statements for everything else, I cannot find one for this. The trigger is something like:
IF (yada yada)
THEN
BEGIN
SELECT a
INTO generic_variable1
FROM table
WHERE condition;
SET generic_variable2 = value1;
EXCEPTION WHEN OTHERS --this part needs to be replaced by valid MySQL syntax
SET generic_variable2 = value2;
END;
END IF;
How do I convert that part into MySQL?
You should understand that MySQL has a very limited stored proc / trigger language compared to Oracle. While porting to MySQL, many Oracle users say over and over again, "I can't believe MySQL can't do X!!!!"
The closest thing to EXCEPTION WHEN OTHERS may be DECLARE CONTINUE HANDLER.
Example (not tested):
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET #generic_variable2 = 1;
But you'd declare that before the block of code that might throw the exception, not after.
See http://dev.mysql.com/doc/refman/5.5/en/declare-handler.html for full docs.

Validate Date at MySQL

How do you validate a date in MySQL ? In SQL Server, we have "ISDATE()" to validate whether the expression is a valid date. What function do we use in MySQL ?
Simply use date(your_date_here) and that will check if a date is valid.
EDIT:
If you really wanna have a isDate returning true or false, you can use this:
CREATE FUNCTION IsDate (sIn varchar(1024)) RETURNS INT
BEGIN
declare tp int;
if (select length(date(sIn)) is null )then
set tp = 0;
else
set tp = 1;
end if;
RETURN tp;
END
cheers
Try a solution like this one I used with Oracle to Sql Server move in SSIS. Dealing with Timestamp/Datetime when copying data from Oracle to SQL Server using SSIS
From your description, Oracle and MySql appear to handle dates similarly.