How to create a function using MySQL Workbench? - mysql

I have an MSSQL background.
I am trying to create a function in MySQL Workbench by rightclicking on 'Functions' > 'Create Function'.
I insert this text to create the function into the window but it says there are errors in sql at the last line missing 'if'.(SQL below). What am I missing?
2nd Qn. (Related)
If I create the function using the function SQL (not using the menu in MySQL Workbench), the function gets created but it doesn't appear in the 'Functions' being shown in the schema am working on.
What is the recommended way to create functions in MySQL Workbench?
Thanks.
CREATE FUNCTION fnIsExcluded(ConcattedString NVARCHAR(15), InValue DECIMAL)
RETURNS BIT
BEGIN
DECLARE individual VARCHAR(20) DEFAULT NULL;
DECLARE ReturnValue BIT;
IF (LENGTH(ConcattedString)) < 1
THEN
SET ReturnValue = 0;
ELSE IF ConcattedString IS NULL
THEN
SET ReturnValue = 0;
ELSE IF InValue IS NULL
THEN
SET ReturnValue = 0;
ELSE
SET ReturnValue = 1;
END IF;
RETURN ReturnValue;
END;

You didn't say what version of MySQL Workbench you are using.
1) The syntax error in the routine editor you is because in older versions the editor did not handle delimiters automatically. Hence you'd need a command to change the default delimiter, like:
delimiter $$
(at the top of the text) to change the default (semicolon) to a custom one (double dollar). The reason you have to do this is that the default delimiter is needed in the function definition and if not changed the client (here MySQL Workbench) would wrongly split your function command into individual commands. However, you can update to the latest MySQL Workbench version (6.2.3 at the time of this writing) to have this handled automatically.
2) Usually changes in the db structure cannot be picked up automatically because it would mean to load all db content at a frequent intervals, which is not feasible for any non-trivial db. Hence you have to trigger this manually, by clicking the refresh button.
However, some changes (especially additions or deletions you did yourself in MySQL Workbench) either are already tracked or will be there in future versions).

Related

mysql stored function syntax for dummies

I am appear to be having a bad case of brain flatulence at the moment. Can someone see the bleedingly obvious error in the following mysql stored function?
delimiter $$
drop function if exists test$$
create function test()
returns boolean
begin
return true;
end$$
I know it is dancing around the place, laughing its head off and waving its bare buttocks in my direction - but I just cant see it.
The original error was in a much larger hunk of code that I have cut down to the above - but I can't seem to remove much more without running out of code to remove.
mysql version 5.7.14
Drop the function before setting the new delimiter
DROP function IF EXISTS `test`;
DELIMITER $$
USE `A_DB`$$
CREATE FUNCTION `test` ()
RETURNS BOOLEAN
BEGIN
RETURN TRUE;
END$$
DELIMITER ;
For anyone who comes this way again the problem turned out not to be with the SQL. The issue was with the driver and my understanding of how mysql hangs together.
The delimiter statement is part of the MySQL client (command line) and is not part of any driver (or at least any on node i can find)
So if you are loading your sql by sucking in a string and squirting it at the database via a driver (nodejs mariasql in my case) then delimiter is not understood.
You either have to parse the delimiters out yourself - or be more elaborate and logon to the mysql client shell somehow and load the file. I will probably simply put a line such as %start sql stuff here %end and parse the sql into chunks - and squirt these at the driver.

Oracle equivalent for MySQL code "insert into dummy" to return error message

I have a couple of hundred triggers in mysql db which i'm migrating to Oracle db. There's an statement that i see a lot which i haven't been able to find an equivalent one in oracle.
INSERT INTO $some_kind_of_message._BD_TRIGG$ (dummy) VALUES (value);
i've seen this also in procedures and functions, and it seems to 'return' a message to the aplication who calls the procedure (i think). i'm kind of new in both RDBMS but i've been working with oracle a couple of months.
Is there an equivalent statement to replace the mysql's one in oracle ? Thanks a lot.
EDIT:
This is an example trigger of many. This one is used for login validation.
I'm not very sure about oracle's trigger syntax but that's not the problem now.
The 'case' part is still in mysql syntax. I havent been able to find information in mysql nor oracle documentation. It is not a normal insert, it is some kind of return message that mysql uses (thats what i guess) and i've seen it also in functions and procedures.
¿How can i replace it for oracle to perform the same task?
CREATE OR REPLACE TRIGGER adduser
BEFORE INSERT
ON tbl_users
FOR EACH ROW
DECLARE flag INTEGER;
begin
flag := 1;
/* validate login */
IF(LENGTH(TRIM(:NEW.login)) < 4) THEN
flag := -1;
END IF;
/* valido clave */
IF(flag = 1) THEN
IF(LENGTH(:NEW.clave) < 3) THEN
flag := -2;
END IF;
END IF;
CASE flag
WHEN -1 THEN INSERT INTO $login_less_then_4_characters._BD_TRIGG$ (dummy) VALUES ('error');
WHEN -2 THEN INSERT INTO $pass_less_then_5_characters._BD_TRIGG$ (dummy) VALUES ('error');
ELSE flag := 0;
END CASE;
END;
I think you need RAISE_APPLICATION_ERROR() function/procedure.
Syntax:
raise_application_error(error code, your error message);
Example:
raise_application_error(-20001, 'Login must have 4 characters or more');
In Oracle custom aplication error codes are between -20000 and -20999.
More information here:
Oracle PL/SQL - Raise User-Defined Exception With Custom SQLERRM
Oracle documentation: link
I'm not familiar with MySQL syntax but in Oracle it translates as
Insert into table_name(column_name) VALUES (value);
where dummy is a column in some table or parameter passed to function. You cannot use procedures, triggers in Insert statements in Oracle. You may use Function() in DML statements, e.g. SELECT your_function(dummy)..., INSERT your_function(dummy)... And function returns a value as we all know.

Function definition not properly passed to MySQL database using MySQL Workbench

I'm using MySQL 5.5 (x64) and MySQL Workbench 5.2 deployed locally on a Windows 7 workstation for development purposes. I used MySQL Workbench to build a schema with the following function definition:
CREATE FUNCTION `db`.`get_public_name` (GPN_entID INT) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
DECLARE GPN_pubName VARCHAR(64);
SELECT public_name INTO GPN_pubName
FROM entity WHERE id_entity=GPN_entID LIMIT 1;
RETURN GPN_pubName;
END
I then attempt to "Forward Engineer" the schema to the database with the following options specified:
DROP Objects Before Each Create Object
Generate DROP SCHEMA
Add SHOW WARNINGS After Every DDL Statement
GENERATE INSERT Statements for Tables
After this, MySQL Workbench attempts to publish to the server:
CREATE FUNCTION `db`.`get_public_name` (GPN_entID INT) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
DECLARE GPN_pubName VARCHAR(64);
SELECT public_name FROM entity WHERE id_entity = GPN_entID;
RETURN GPN_pubName;
END
This results in the following error:
Executing SQL script in server
ERROR: Error 1415: Not allowed to return a result set from a function
Upon closer examination, I noticed the "INTO" and "LIMIT" clauses of the SELECT statement have been removed from the original function definition. This looks like it might be a cached version of the function, but I have tried everything I can think of (short of uninstalling and reinstalling MySQL Workbench) to flush any such cache to reload the correct version, but to no avail.
So, why is this change happening and how do I prevent it from happening?
Try changing to this:
SELECT public_name FROM entity WHERE id_entity = GPN_entID LIMIT 1 INTO GPN_pubName;
I'm embarrassed; if it wasn't for the fact this may be useful to others, I'd just go ahead and delete this question to hide my shame.
It turns out I created two functions with the same name and MySQL Workbench happily let me do so. I didn't notice that was the case until I started going through the stored routines with a more careful eye. I was editing one, but the other one (which had the error) was never changed. Since publishing each function involved dropping any earlier version from the database, I probably wouldn't have noticed this until things weren't working properly.

If conditional in SQL Script for Mysql

In a sql script that does sequential execution, is there a way one can introduce an IF THEN ELSE conditional to control the flow of query execution?
I happened to run into this http://www.bennadel.com/blog/1340-MySQL-Does-Not-Support-IF-ELSE-Statements-In-General-SQL-Work-Flow.htm
which says that the IF THEN ELSE will not work in a sql script.
Is there another way around?
Basically, I want to run a particular "select colName from table" command and check if colName corresponds to a particular value. If it does, proceed with the rest of the script. Else, halt execution.
Please advise.
I just wrap my SQL script in a procedure, where conditional code is allowed. If you'd rather not leave the statements lying around, you can drop the procedure when you're done. Here's an example:
delimiter //
create procedure insert_games()
begin
set #platform_id := (select id from platform where name = 'Nintendo DS');
-- Only insert rows if the platform was found
if #platform_id is not null then
insert into game(name, platform_id) values('New Super Mario Bros', #platform_id);
insert into game(name, platform_id) values('Mario Kart DS', #platform_id);
end if;
end;
//
delimiter ;
-- Execute the procedure
call insert_games();
-- Drop the procedure
drop procedure insert_games;
If you haven't used procedures, the "delimiter" keyword might need some explanation. The first line switches the delimiter to "//" so that we can include semi-colons in our procedure definition without MySQL attempting to interpret them yet. Once the procedure has been created, we switch the delimiter back to ";" so we can execute statements as usual.
After doing some research I think I may have found a way to work around this. I was looking for a way to verify if a script had already executed against a target database. This will be primarily for version control of my databases. I have a table created to keep track of the scripts that have been executed and wanted some flow inside my scripts to check that table first before execution. While I have not completely solved the problem yet I have created a simple script that basically does what I need, I just need to wrap the DDL into the selects based on the value of the variables.
step 1 - Setup a bit variable to hold the result
step 2 - do your select and set the variable if the result is found
step 3 - Do what you need to do on false result
step 4 - Do what you need to do on true result
Here is the example script
set #schemachangeid = 0;
select #schemachangeid := 1 from SchemaChangeLog where scriptname = '1_create_tables.sql';
select 'scriptalreadyran' from dual where #schemachangeid = 1;
select 'scriptnotran' from dual where #schemachangeid = 0;
I also recognize this is an old thread but maybe this will help someone out there trying to do this kind of thing outside of a stored procedure like me.

MySQL query browser procedure error code -1

I'm having a rather strange problem with MySQL. Trying to create a procedure to update some fields in the database (the code is below).
The problem is with the line that is currently commented. It seems that if no SELECT statements get executed during the procedure MySQL query browser will return an error code of "-1, error executing SQL query".
I tried the same thing in HeidiSQL and the error was "cannot return result set". So I suppose the question is do I always have to select something in the procedure, or is there some other thing I missed.
The query works fine when the comment is removed.
DELIMITER /
DROP PROCEDURE IF EXISTS updateFavourites /
CREATE PROCEDURE updateFavourites(quota INT)
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE artist_id,releases INT;
DECLARE c_artist Cursor FOR
SELECT Artist.id_number,COUNT(Artist.id_number) FROM Artist
JOIN CD ON CD.is_fronted_by = Artist.id_number
GROUP BY Artist.id_number;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000'
SET done=1;
IF quota > 0 THEN
OPEN c_artist;
REPEAT
FETCH c_artist INTO artist_id,releases;
IF NOT done THEN
IF releases >= quota THEN
UPDATE CD SET CD.rating='favourite' WHERE CD.is_fronted_by = artist_id;
END IF;
END IF;
UNTIL done END REPEAT;
CLOSE c_artist;
-- SELECT 'Great success';
ELSE
SELECT CONCAT('\'quota\' must be greater than 0.',' Got (',quota,')');
END IF;
END /
DELIMITER ;
Here's the sql to create the tables and some data:
DROP TABLE IF EXISTS CD;
DROP TABLE IF EXISTS Artist;
CREATE TABLE Artist (
id_number INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
);
CREATE TABLE CD (
catalog_no INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY,
is_fronted_by INT UNSIGNED,
rating ENUM ('favourite','top draw','good','so-so','poor','rubbish'),
CONSTRAINT fk_CD_Artist FOREIGN KEY (is_fronted_by) REFERENCES Artist(id_number) ON UPDATE CASCADE
);
INSERT INTO Artist VALUES(11,'Artist 1');
INSERT INTO Artist VALUES(10,'Artist 2');
INSERT INTO CD VALUES (7,11, 'top draw');
INSERT INTO CD VALUES (650,11,'good');
INSERT INTO CD VALUES (651,11,'good');
INSERT INTO CD VALUES (11,10,'favourite');
Query Browser is not for running scripts, just single query.
I tried your code by moving cursor into each query (except DELIMITER) and pressing Ctrl+Enter.
It created that stored procedure without problem. (just refresh schema on the left).
If you wish creating procedure, use menu "Script"->"Create stored procedure/function".
But better forget about QueryBrowser it is not supported at all (and actunally not useful).
If you have decent hardware and plenty resources, try Workbench 5.2 otherwise use SQLyog
Googling around, there are several reports of the same error, but little information to solve the problem. There's even a bug logged at mysql.com but it appears to have been abandoned without being resolved.
There's another StackOverflow question on the same error, but it's also unresolved.
All it means is that there is no result set from the query. Looking at the source code, it appears that sometimes an error status of MYX_SQL_ERROR is set when the query has no result set. Perhaps this is not an appropriate consequence?
I notice that when I use the mysql command-line client, it yields no error for calling a proc that returns no result set.
update: I tried to revive that MySQL bug report, and provide a good test case for them. They changed the bug from "no feedback" to "verified" -- so at least they acknowledge it's a bug in Query Browser:
[11 Dec 9:18] Sveta Smirnova
Bill,
thank you for the feedback. Verified
as described.
Although most likely this only be
fixed when MySQL Query Browser
functionality is part of MySQL
workbench.
I guess the workaround is to ignore the -1 error, or to test your stored procedures in the command-line mysql client, where the error does not occur.
The comment supposes the issue will disappear as the Query Browser functionality becomes part of MySQL Workbench. This is supposed to happen in MySQL Workbench 5.2. I'll download this beta and give it a try.
MySQL Workbench 5.2 is in Beta, but I would assume MySQL engineering can't predict when the Beta will become GA. Those kinds of predictions are hard enough under standard conditions, but there's a lot of extra uncertainty of MySQL's fate due to the unresolved Oracle acquisition.
update: Okay, I have tried MySQL Workbench 5.2.10 beta. I executed a stored procedure like this:
CREATE PROCEDURE FooProc(doquery SMALLINT)
BEGIN
IF doquery THEN
SELECT * FROM Foo;
END IF;
END
When I CALL FooProc(0) the response is no result set, and the status is simply "OK".
When I CALL FooProc(1) the response is the result of SELECT * FROM Foo as expected.
However, there's another bug related to calling procedures. Procedures may have multiple result sets, so it's hard to know when to close the statement when you execute a CALL query. The consequence is that MySQL Workbench 5.2 doesn't close the statement, and if you try to do another query (either CALL or SELECT) it gives you an error:
Commands out of sync; you can't run this command now.
MySQL doesn't support multiple concurrent open queries. So the last one must be closed before you can start a new one. But it isn't closing the CALL query. This bug is also logged at the MySQL site.
The bug about commands out of sync has been resolved. They say it's fixed in MySQL Workbench 5.2.11.
Try putting BEGIN and END blocks around the multiple statements in the IF block as such:
IF quota > 0 THEN
BEGIN
OPEN c_artist;
REPEAT
FETCH c_artist INTO artist_id,releases;
IF NOT done THEN
IF releases >= quota THEN
UPDATE CD SET CD.rating='favourite' WHERE CD.is_fronted_by = artist_id;
END IF;
END IF;
UNTIL done END REPEAT;
CLOSE c_artist;
END;
ELSE
SELECT CONCAT('\'quota\' must be greater than 0.',' Got (',quota,')');
END IF;