Creating MySQL Function - mysql

I am trying to write a function that looks for a value assigned to its configuration in a parent-child tree, if the value is null or empty it looks one level up for the value.
I am currently getting syntax errors when trying to create the function.
This is what i have so far,
DELIMITER //
CREATE FUNCTION `db`.`Configuration`(
`ColumnName` VARCHAR(128),
`CID` INT
)
RETURNS VARCHAR(256)
NOT DETERMINISTIC
BEGIN
DECLARE Config VARCHAR(256) DEFAULT NULL;
DECLARE Parent INT;
WHILE (#Config IS NULL OR #Config = "") DO
SELECT #ColumnName INTO #Config, `ParentID` INTO #Parent FROM `Table` WHERE `ID`=#CID;
END WHILE;
RETURN CONCAT(#Config, '::', #Parent);
END ;
//
DELIMITER ;
I am getting the following error when I try to add the function:
1327 - Undeclared variable: ParentID
Any help would be greatly appreciated!

You receive the error message in the question because you have multiple into clauses, whereas according to mysql manual on select ... into ... you can only have one. So, to get rid of this specific error message you nee to rewrite your select statement as:
SELECT #ColumnName, `ParentID` INTO #Config, #Parent FROM `Table` WHERE `ID`=#CID;
However, there are some further issues with your code:
varname and #varname do not refer to the same variable. The first one is either a function / stored proc parameter or local variable, while the 2nd one is a user-defined variable. In your code you must remove the # from the variable names.
You cannot use a variable in place of a field name in an sql statement. You must use dynamic sql with prepared statements to achieve this. See the following SO question on how to this: How To have Dynamic SQL in MySQL Stored Procedure
You do not overwrite CID parameter in your while loop. This means that if the first iteration the configuration will remain null, then you have an infinite loop. You should change the value of CID in your loop.
I cannot guarantee that there are no further errors in your code.

There are a few problems with your function:
You are using SELECT...INTO incorrectly. When selecting multiple values you should only use INTO once. For example SELECT a,b into #a,#b FROM...
You are using user-defined variables with similar names to your function parameters, but they are not the same thing. In your code CID and #CID are different. I suggest using standard naming prefixes to clarify this: for example use p_ for function parameters and v_ for local function variables. You shouldn't need to use user-defined variables at all.
Your WHILE loop is bound to lead to infinite loops since the query criteria never changes. If it returns NULL or empty string once, it will keep returning them forever.
Here's a quick rewrite to address the above issues. I'll leave it to you to implement the WHILE loop correctly:
DELIMITER //
CREATE FUNCTION `db`.`Configuration`(
p_column_name VARCHAR(128),
p_id INT
)
RETURNS VARCHAR(256)
READS SQL DATA
BEGIN
DECLARE v_config VARCHAR(256) DEFAULT NULL;
DECLARE v_parent INT;
SELECT p_column_name,`ParentID`
INTO v_config, v_parent
FROM `Table`
WHERE `ID`=p_id;
RETURN CONCAT(v_config, '::', v_parent);
END ;
//
DELIMITER ;

Related

Receiving "Error Code: 1111 Invalid use of group function" when creating a stored function in a music database [duplicate]

I have a mysql table of employees with columns surname and workhours for each employee . I am trying to create a stored function that takes a letter as input and returns the sum of workhours of all employees whose surname starts from the input letter .This is basically an easy task but I am a complete beginner in sql and I need your help .
What I tried :
CREATE FUNCTION sumOfTotalSickHours(letter CHAR(1))
RETURNS DOUBLE DETERMINISTIC
BEGIN
DECLARE total DOUBLE DEFAULT 0
SELECT SUM(sickleavehours) INTO total
FROM employee where lastName LIKE '#letter%'
RETURN total
END
With my above code I get a syntax error since I do not know how to write the query correctly .
First of all, each statement needs to end with a semicolon (;).
Be sure you read https://dev.mysql.com/doc/refman/8.0/en/stored-programs-defining.html to understand how to use DELIMITER when defining stored programs.
Also to reference an input variable, don't put inside quotes.
And don't use #letter because variables with the # sigil are not the same variable as without the sigil.
So for example:
CREATE FUNCTION sumOfTotalSickHours(letter CHAR(1))
RETURNS DOUBLE DETERMINISTIC
BEGIN
DECLARE total DOUBLE DEFAULT 0;
SELECT SUM(sickleavehours) INTO total
FROM employee where lastName LIKE CONCAT(letter, '%');
RETURN total;
END

MySQL Call procedure inside function for count

Is it possible to use a procedure inside a function? For example, I would like to gather all my rows related to an id but I would also like to count the rows and use it in a select statement. This is not working:
drop procedure if exists relatives;
create procedure relatives(in parent int(11),out counted int(11))
begin
set counted=(select count(*) from category where related=parent);
end;
drop function if exists relatives_count;
create function relatives_count(parent parent(11)) returns int(11)
begin
declare count int(11);
call relatives(parent,counted);
return counted;
end;
So that I can use the count
select relatives_count(id) from category
This is just for curiosity purposes. It may look senseless since I can just call a single select query and get the same results but I want to know how I can use my procedure out variable in a function.
Yes, a MySQL FUNCTION can call a MySQL PROCEDURE.
But... the operations the procedure performs will be limited to the operations allowed by a function. (We can't use a procedure to workaround the limitations placed on a function.)
"is not working" is so nebulously vague as to be practically useless in debugging the issue. What exact behavior is being observed?
My suspicion is that the SQL statements shown are failing, because there is no override for the default statement delimiter.
Also, parent(11) is not a valid datatype.
Be aware that when an identifier for a column in a SQL statement in a MySQL stored program matches an identifier used for an argument or local variable, MySQL follows a rule about which (the column name or the variable) that is being referenced.
Best practice is to adopt a naming convention for arguments and local variables that do not match column names, and to qualify all column references with a table name or table alias.
Personally, I use a prefix for arguments and local variables (a for argument, l for local, followed by a datatype i for integer, d for date/datetime, n for decimal, ...
DELIMITER $$
DROP PROCEDURE IF EXISTS relatives$$
CREATE PROCEDURE relatives(IN ai_parent INT(11),OUT ai_counted INT(11))
BEGIN
SELECT COUNT(*)
INTO ai_counted
FROM category c
WHERE c.related = ai_parent
;
END$$
DROP FUNCTION IF EXISTS relatives_count$$
CREATE FUNCTION relatives_count(ai_parent INT(11))
RETURNS INT(11)
BEGIN
DECLARE li_counted INT(11);
CALL relatives(ai_parent,li_counted);
RETURN li_counted;
END$$
DELIMITER ;
Please identify the exact behavior you observe. Error message when creating the procedure? Error message when executing the function? Unexpected behavior. That's much more precise and informative than telling us something "is not working".

Simple sql function with SELECT

I try to understand how functions work. I can make the equivalent in procedure but I can't create a simple function with select.
element is UNIQUE and
thing is PRIMARY
CREATE DEFINER=`root`#`localhost`
FUNCTION `get_element_by_thing`(`thing` VARCHAR(255))
RETURNS VARCHAR(255)
CHARSET utf8
NOT DETERMINISTIC
READS SQL DATA
SQL SECURITY DEFINER
DECLARE #return_element VARCHAR(255);
SET #return_element = (
SELECT
`element`
FROM
`table1`
WHERE
`thing` = thing
);
RETURN #return_element;
I use the phpmyadmin interface.
1) Don't declare user-defined variables.
The name of a local variable in MySQL stored program does not start with an at sign #. As an example:
DECLARE stored_program_local_variable VARCHAR(255);
SET stored_program_local_variable = 'somevalue';
The name of a user-defined variables start with an at sign #. (The at sign character is what distinguishes user-defined variables from other identifiers.) It's not valid to declare a user-defined variable in a stored program. To create a user-defined variable, just assign a value to it. For example:
SET #user_defined_variable = 'somevalue';
2) If we don't need to persist variables beyond the scope of a stored program, we typically use local variables, which exist only for the duration of the stored program execution. (Which is different behavior than user-defined variables which are at the session level.)
3) Use the SELECT ... INTO syntax to retrieve scalar values into user-defined or local variables. https://dev.mysql.com/doc/refman/5.7/en/select-into.html
Try:
DELIMITER $$
CREATE DEFINER=`root`#`localhost`
FUNCTION `get_element_by_thing`(`thing` VARCHAR(255))
RETURNS VARCHAR(255)
...
BEGIN
DECLARE return_element VARCHAR(255) ;
SELECT t1.element
INTO return_element
FROM table1 t1
WHERE t1.thing = thing
LIMIT 1 ;
RETURN return_element ;
END $$
DELIMITER ;
Note: with ambiguous identifiers (i.e. routine parameter and column with the same name in a SQL statement, the routine parameter takes precedence over the column name. Qualify the column reference with the table name or table alias so it's not ambiguous. I prefer to assign routine parameters (and local variables) names that do not match column names.
If for some reason you need to assign a value to a user-defined variable in a SQL statement, you can use the := assignment operator. This is also valid outside the context of a stored program.
SELECT #user_defined_variable := t.somecolumn
FROM mytable t
WHERE somecondition
ORDER BY someexpression
LIMIT 1

MySQL stored procedure with OUT parameter

I keep getting a null value when using an out parameter.
CREATE PROCEDURE `getTotalPoints`(IN `uEmail` VARCHAR(255), OUT `iTotal` DECIMAL(5,2) UNSIGNED)
begin
select
coalesce(
coalesce(sum(points_earned),0) -
coalesce(sum(points_lost),0) +
coalesce(sum(points_taken),0) -
coalesce(sum(points_traded),0),0)
from user_activities
where user_email=#uEmail into #iTotal;
end
I know the select statement works fine as without the out parameter, I get 0.00 as a result.
I'm sure it's something simple, but everything I've researched and tried has resulted in the same NULL return value.
Remove the "#" symbols on the variable references.
"#uEmail" and "#iTotal" are references to user-defined variables, not the procedure arguments.
You want to reference the procedure arguments as "uEmail" and "iTotal", without the "#".
Or, you could probably get your statement to work if you did the necessary assignments to and from the user-defined variables, something like this in the body of the procedure:
-- set user-defined variable to value from procedure argument
SET #uEmail = uEmail;
-- statement references user-defined variables
SELECT ...#uEmail ... INTO #iTotal;
-- set procedure OUT argument from user-defined variable
SET iTotal = #iTotal;

Creating a user-defined function in MySQL to handle auto_increment

I am trying to create a user-defined function in MySQL in order to generate unique numbers. As the auto_increment feature of MySQL just increments its seed by one, I need to have such a function to handle fields that need to be incremented by more than one. Here is my SQL script:
DELIMITER $$
CREATE FUNCTION `getUniqueID`(
id_type CHAR(1)
) RETURNS INT(10)
BEGIN
DECLARE run INT(10);
START TRANSACTION;
SELECT unique_gen_id INTO #run FROM tbl_unique_seed WHERE id_type = #id_type;
UPDATE tbl_unique_seed SET unique_gen_id = (unique_gen_id + 1) WHERE id_type = #id_type;
COMMIT;
RETURN run;
END$$
DELIMITER ;
I do not have much experience in MySQL, but creating this kind of functions in SQL Server is quite easy. It will be nice of you to help me figure out a solution for this issue. Currently, I am facing some syntax errors. The most basic ones relate to the syntax of my transaction and the select statement.
See the docs here: http://dev.mysql.com/doc/refman/5.0/en/replication-options-master.html#sysvar_auto_increment_increment
You can change the value of auto_increment_increment, which is normally 1.