MySQL Routines in phpmyadmin - Unresolved Declare Error - mysql

I'm using phpmyadmin Routines to write a Stored Procedure called ViewUserAccounts.
I am continuously getting ambiguous error messages.
I have one IN parameter named USERNAME of type VARCHAR(45).
The text within the definition box includes:
DECLARE TempUserID INT DEFAULT 0
SET TempUserID = (SELECT idUser FROM User WHERE User.Username = USERNAME)
SELECT * FROM Account WHERE Account.idUser = TempUserID

Well...figured it out myself!
DECLARE requires a BEGIN and END and the DECLARE statement must be directly after the BEGIN statement. In addition, all lines required a semi-colon.

Related

MySQL Stored Procedure - increment a variable

Why is my stored procedure erroring on the last two lines. Am i missing something? I am trying to write something that takes my basis name and creates a variable that increments it by 1 and continues until it hits 150. I know how to do this in Microsft SQL which might be where my syntax errors are coming from. Thanks.
USE repo;
DELIMITER $$
Create DEFINER = 'root' # 'localhost' procedure csvOutput()
BEGIN DECLARE basis_name int; SET #basis_name = 0;
if basis_name < 150 then
set basis_name = basis_name + 1;
SELECT *
FROM
(SELECT
'cbt.component',
'fl.input_flow',
'ft.flow',
'Function_ID',
'sf.subfunction',
'fl.output_flow',
'ft2.flow',
'# of times it appears',
'sf.tier'
UNION ALL (SELECT
cbt.component,
fl.input_flow,
ft.flow,
sf.id AS 'Function ID',
sf.subfunction,
fl.output_flow,
ft2.flow,
COUNT(a.name) AS '# of times it appears',
sf.tier
FROM
artifact a, function fu, flow fl, flow_type ft, subfunction_type sf, flow_type ft2, comp_basis_type cbt
WHERE
a.id = fu.describes_artifact
AND fu.id = fl.describes_function
AND fl.input_flow = ft.id
AND fl.output_flow = ft2.id
AND fu.subfunction_type = sf.id
AND a.basis_name = 115
AND fu.supporting = 0
AND a.basis_name = cbt.id
AND sf.tier >= 3
GROUP BY fl.input_flow
ORDER BY COUNT(fu.id) DESC)) resulting_set INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 5.7/Uploads/test4.csv' FIELDS ENCLOSED BY '"' TERMINATED BY ',' ESCAPED BY '"' LINES TERMINATED BY '';
END$$
Delimiter;
I tested your statement. For future reference, when you ask about an error on Stack Overflow, please include the error.
This is the error I got from testing:
ERROR 1064 (42000): 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 'DECLARE basis_name int; SET #basis_name = 0;
I see the problem, it's actually on this line:
USE repo; DELIMITER $$ Create DEFINER = 'root' # 'localhost' procedure csvOutput()
Keep in mind that DELIMITER sets the statement delimiter to all of the following text until end of line. So you have set the delimiter not to $$, but to the entire string: $$ Create DEFINER = 'root' # 'localhost' procedure csvOutput()
The error reports some problem with DECLARE because it's trying to start a new statement, not part of the procedure. BEGIN TRANSACTION is a legal statement, but other than that, BEGIN cannot be used on its own in MySQL. So BEGIN DECLARE... caused MySQL to say, "whoah, that's not what I expect you to add after BEGIN!"
Just add a newline after DELIMITER $$
Also note that you must not use a semicolon after the DELIMITER statement because that will become part of your statement terminator too. How else could you set the delimiter back to ;?
Another issue that would help you in the future, but it is not the root cause of the error you asked about:
In MySQL, basis_name and #basis_name are two different variables.
Variables declared with DECLARE within a procedure don't have the # prefix. You use them without the prefix when you declare them and when you use them. These variables are local to the stored procedure where they are declared.
Variables with the # prefix don't need to be declared. These are called "user-defined variables". You can create them merely by assigning a value to an identifier. You must always use the # prefix when you reference these variables. These variables are not local to the procedure where you set them. They retain their value in your current session after the procedure has finished. You can set their value and read their value with simple SQL statements outside a procedure.
This is a common issue on which Microsoft users get confused when moving to MySQL.

Use IN param in WHERE clause inside MySQL stored procedure

I am using MySQL with HeidiSQL and I want to create a stored procedure that takes one String param and returns a table. This is what I have tried:
CREATE PROCEDURE sp(IN in_param VARCHAR(50))
BEGIN
SELECT * FROM fact_table ft
WHERE ft.param = #in_param
END
And I called it like this:
CALL sp('string_param');
The procedure returns an empty table, as #in_param is somehow NULL inside the SP.
I also like this: WHERE ft.param = in_param, but the I got an error when I ran it, saying SQL Error (1054): Unknown column 'in_param' in 'where clause'
Can someone tell me what I'm doing wrong?
PS:
I tried creating it by hand, and also using Heidi's Create new -> Stored routine wizard
I finally found out a solution that works:
CREATE PROCEDURE sp(IN in_param VARCHAR(50))
BEGIN
DECLARE declared_in_param CHAR(50);
SET declared_in_param = in_param;
SELECT * FROM fact_table ft
WHERE ft.param = declared_in_param;
END
So, the idea was to declare and set a new variable to that IN param, and use that declared variable inside the WHERE clause of the SELECT statement.
I haven't had time to research WHY this works, but I will

MySql syntax error on procedure parameter

I am trying to write a simple procedure but am encountering a syntax error at the first parameter. As best I can tell I'm following the syntax of CREATE PROCEDURE correctly.
I am limited to accessing my database with phpMyAdmin. Here is the create script I'm trying to run:
DROP PROCEDURE IF EXISTS product_index_swap/
CREATE PROCEDURE product_index_swap (#id INT, #oldIndex INT, #newIndex INT)
BEGIN
DECLARE #swapID;
SET #swapID = (SELECT `id` FROM `product` WHERE `order_index` = #newIndex LIMIT 1);
UPDATE `products` SET `order_index` = (CASE WHEN `id` = #id THEN #newIndex
WHEN `id` = #swapID THEN #oldIndex END)
WHERE `id` IN (#id, #swapID);
END
I am using the option on phpMyAdmin to change the delimiter to /.
I receive a syntax error "near '#id INT, #oldIndex INT....". I thought I may encounter more delimiter errors since I'm not entirely clear on the scope of them. I believe if that was the problem the error would be on a new line in the procedure when it failed to understand a semicolon, not at the parameters declaration.
You're using the Microsoft SQL Server convention of putting # before all the parameters and local variables. MySQL doesn't do this.
In MySQL syntax, procedure parameters have no sigil.
Also parameters are typically declared IN or OUT or INOUT.
CREATE PROCEDURE product_index_swap (IN id INT, IN oldIndex INT, IN newIndex INT)
BEGIN
DECLARE swapID;
...
MySQL variables that have the # sigil are session variables.
See also:
https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
https://dev.mysql.com/doc/refman/5.7/en/declare-local-variable.html
https://dev.mysql.com/doc/refman/5.7/en/set-variable.html
In MySQL, the #var variables are session level variables.
Use normal variables without the # and make sure you do not have conflict with column names:
CREATE PROCEDURE product_index_swap (in_id INT, in_oldIndex INT, in_newIndex INT)
BEGIN
DECLARE v_swapID int;
SELECT id into v_swapID
FROM product
WHERE order_index = in_newIndex
LIMIT 1;
UPDATE products
SET order_index = CASE WHEN id = in_id THEN in_newIndex
WHEN id = v_swapID THEN in_oldIndex
END
WHERE id IN (in_id, v_swapID);
END

Do temporary tables make functions non deterministic in MySQL

I want to create a stored function in MySQL. I've been granted ALL PRIVILEGES, what I think contains also the required SUPER privilege. And binary logging is enabled.
While creating a function I get the 1419 error:
Error Code: 1419. You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
I read through the MySQL manuals and it looks like this binary logging issue should only apply to NOT DETERMINISTIC functions, which change data.
I've created a simple example function which points out my question more clearly:
DROP FUNCTION IF EXISTS getIdTest;
DELIMITER $$
CREATE FUNCTION getIdTest( pv_order_nr VARCHAR( 45 ) )
RETURNS INT UNSIGNED
COMMENT 'Gets an order number and returns an ID'
DETERMINISTIC READS SQL DATA
BEGIN
DECLARE lv_id INT UNSIGNED;
-- DOES THIS COMMAND MAKE THE FUNCTION NOT-DETERMINISTIC?
CREATE TEMPORARY TABLE tmp_log(
order_nr VARCHAR(45)
, message VARCHAR(255)
, created_at DATETIME
);
-- AND/OR DOES THIS COMMAND MAKE THE FUNCTION NON-DETERMINISTIC?
INSERT INTO tmp_log
SET order_nr = pv_order_nr
, message = CONCAT( 'Id read for order ', pv_order_nr, '.')
, created_at = NOW();
SELECT so.id_sales_order
INTO lv_id
FROM sales_order AS so
WHERE so.order_nr = pv_order_nr
LIMIT 1;
RETURN lv_id;
END
$$
DELIMITER ;
As you see my function is declared as DETERMINISTIC.
My question is, does the second statement in the function routine body (CREATE TEMPORARY TABLE) make the function NOT DETERMINISTIC?
If I omit this statement, does the third statement (INSERT INTO --a temporary table--) make the function NOT DETERMINISTIC as well?
Thanks for reading this :)
Felix

Mysql UDF to return record id if exists else insert and return recordid`

I am trying to write a Mysql Function to return a contactID if the record exists based on the parameters supplied, If the record is not present, I am adding the record and then returning the contactID of the new record.
But the function is throwing 1048error, Can you check and correct me if I went wrong in writing this.
DELIMITER $$
CREATE DEFINER=`root`#`%` FUNCTION `GetContactID`(accountNumber CHAR(45),UserID INT(11)) RETURNS char(1) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE ContactID INT DEFAULT 0;
SELECT ContactID INTO #ContactID FROM Contact WHERE AccountNumber = #accountNumber AND UserID = #UserID AND Status =1;
IF ContactID = 0 or ContactID is null THEN
INSERT INTO Contact(AccountNumber,UserID) VALUES (#accountNumber,#UserID);
SELECT ContactID INTO #ContactID FROM Contact WHERE AccountNumber = #accountNumber AND UserID = #UserID;
END IF;
RETURN ContactID;
END
Can someone help me where I went wrong.
Thanks
The problem results from mixing user variables, local variables and parameters.
#UserId is not the same as UserId - they are different variables.
UserId is also a name of column in the table.
User defined variables are wirtten as #var_name, are stored in the user session and can be used to pass values between differend stored routines that reference them, see this link for details: http://dev.mysql.com/doc/refman/5.7/en/user-variables.html
local variables are declared in stored routines using DECLARE keyword, their scope is local within the stored routine, see this link for details: http://dev.mysql.com/doc/refman/5.7/en/declare-local-variable.html
Parameters of function/procedure - they are declared in the procedure/function declaration, they are used to pass parameters to the stored routine from the caller, can be also used to return results from the routine to the caller (if declared as OUT or INOUT). Their scope is similar to local variables. For details see this link: http://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
Try this code:
DELIMITER $$
CREATE DEFINER=`root`#`%` FUNCTION `GetContactID`(p_accountNumber CHAR(45),p_UserID INT(11)) RETURNS char(1) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE v_ContactID INT DEFAULT 0;
SELECT ContactID INTO v_ContactID
FROM Contact
WHERE AccountNumber = p_accountNumber AND UserID = p_UserID AND Status =1;
IF v_ContactID = 0 or v_ContactID is null THEN
INSERT INTO Contact(AccountNumber,UserID)
VALUES (p_accountNumber,p_UserID);
SELECT ContactID INTO v_ContactID FROM Contact
WHERE AccountNumber = p_accountNumber AND UserID = p_UserID;
END IF;
RETURN v_ContactID;
END;
Notice that:
function parameters are declared with prefix p_
local variables are declared with prefix v_
the function doesn't use any user variables (prefixed by #)
These prefixes help to avoid ambiguity - we know that p_UserID is a parameter, v_UserId is a local variable, and UserID is a column name in the table (If we would use #UserId, we knew that this was the user variable).