MySQL PROCEDURE using IF Statement with #Parameter Not Working - mysql

Why is the data not being inserted on the table when I execute the procedure, what seems to be lacking with the code?
I'm testing the procedure on phpMyAdmin > myDatabase > Procedures "Routines Tab" and clicking "Execute", prompts with a modal and ask for the values of "#idproc and #nameproc.
I tried with just the INSERT code it works, but when I add the IF condition it doesn't work.
Using XAMPP 8.0.3,
10.4.18-MariaDB
DELIMITER $$
CREATE DEFINER=`root`#`localhost:3307` PROCEDURE `testproc`(IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
IF #idproc = 0 THEN
INSERT INTO testproc(
id,
name)
VALUES(
#idproc,
#nameproc
);
ELSE
UPDATE testproc
SET
id = #idproc,
name = #nameproc
WHERE id = #idproc;
END IF;
SELECT * FROM testproc;
END$$
DELIMITER ;

You mix local variables (their names have not leading #) and user-defined variables (with single leading #). This is two different variable types, with different scopes and datatype rules. Procedure parameters are local variables too.
So when you use UDV which was not used previously you receive NULL as its value - and your code works incorrectly. Use LV everywhere:
CREATE DEFINER=`root`#`localhost:3307`
PROCEDURE `testproc` (IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
IF idproc = 0 THEN
INSERT INTO testproc (name) VALUES (nameproc);
ELSE
UPDATE testproc SET name = nameproc WHERE id = idproc;
END IF;
SELECT * FROM testproc;
END
You do not check does specified idproc value exists in the table. If it is specified (not zero) but not exists then your UPDATE won't update anything. Assuming that id is autoincremented primary key of the table I recommend to use
CREATE DEFINER=`root`#`localhost:3307`
PROCEDURE `testproc` (IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
INSERT INTO testproc (id, name)
VALUES (idproc, nameproc)
ON DUPLICATE KEY
UPDATE name = VALUES(name);
SELECT * FROM testproc;
END
If specified idproc value exists in id column the row will be updated, if not then the new row will be inserted.
Additionally - I recommend you to provide NULL value instead of zero when you want to insert new row with specified nameproc value. NULL always cause autoincremented primary key generation whereas zero needs in specific server option setting.

Related

Unable to diagnose the problem with MySQL stored procedure

I have defined the following stored procedure to add/update a table called ImportedProduct.
If the primary key, ImportedProductId is provided and is greater than zero, then update the exiting record otherwise insert a new one:
DELIMITER //
CREATE PROCEDURE AddOrUpdateImportedProduct (
IN ImportedProductId BIGINT,
IN UniqueThirdPartyCode VARCHAR(64),
IN BranchId BIGINT
)
BEGIN
IF ImportedProductId <= 0 THEN
INSERT INTO ImportedProduct(UniqueThirdPartyCode, BranchId)
VALUES(UniqueThirdPartyCode, BranchId);
ELSE
UPDATE
ImportedProduct
SET
UniqueThirdPartyCode = UniqueThirdPartyCode,
BranchId = BranchId
WHERE
ImportedProductId = ImportedProductId;
END IF;
END //
DELIMITER ;
Now I run the following code to update an existing row:
CALL AddOrUpdateImportedProduct (1, 'y-105', 24);
I can see that the record with with ImportedProductId = 1 exists in the table, but I am getting the following error:
You are using safe update mode and you tried to update a table without
a WHERE that uses a KEY column To disable safe mode
I am pretty sure ImportedProductId = ImportedProductId holds always.. Perhaps rename your variable or add an alias to the updated table.

mysql procedure with if condition

I'm in my first databases class and I'm trying to write a conditional block for a mysql procedure.
This is the procedure:
delimiter //
CREATE PROCEDURE add_ascent(IN cid INT, IN pid INT)
BEGIN
DECLARE count_ascents INT;
SET count_ascents = 0;
SELECT COUNT(`cid`) INTO count_ascents FROM ascents WHERE `cid`=cid AND `pid`=pid;
IF count_ascents < 1 THEN
INSERT INTO ascents (`cid`, `pid`) VALUES (cid, pid);
UPDATE climbers SET climbers.ascents = climbers.ascents + 1 WHERE climbers.id=cid;
UPDATE problems SET problems.ascents = problems.ascents + 1 WHERE problems.id=pid;
END IF;
END;
//
delimiter ;
The goal of the procedure is to only perform the insert and updates if the (cid, pid) pair is not in the the ascents database. After testing, the program doesn't seem to go into the if block at all.
FYI, you might want to consider using an UPSERT, instead of "select/if/insert". For example, mySQL offers INSERT ON DUPLICATE KEY UPDATE.
Here, I suggest:
giving your parameters a DIFFERENT name than the column name, for example iCid and iPid, then
Typing SELECT COUNT(cid) INTO count_ascents FROM ascents WHERE cid=iCid AND pid=iPid and checking the result.

user defined function in insert command

I created a function:
DELIMITER $$
DROP FUNCTION IF EXISTS `heena`.`customer_id`$$
CREATE DEFINER=`root`#`localhost` FUNCTION `heena`.`customer_id`(
a varchar(20),
b varchar(20)
) RETURNS varchar(50) CHARSET latin1
DETERMINISTIC
BEGIN
RETURN CONCAT(
(select ((id), 0) + 1
from heenaj),
substring(a,1,2),
substring(b,1,2));
END;$$
DELIMITER ;
The code executed fine, but when I'm inserting a value using:
insert into heenaj
(c_id,name,number)
values
(customer_id121("abcd",9868275817),"abcd",9868275817);
It shows an error:
Column 'c_id' cannot be null
There's something wrong with your RETURN.
Maybe you are meaning to do this, although I am only guessing:
RETURN CONCAT(
(select ifnull(max(id), 0) + 1
from heenaj),
substring(a,1,2),
substring(b,1,2));
sqlfiddle
Then, you're calling customerid121() not customer_id(). Could this be typo?
Also, in looking at what you're trying to do: do you want your id as auto_increment and just want to have c_id as the id, concatenated with first 2 characters of name and concatenated with first 2 characters of number?
I suggest another solution. It might be nicer to drop your function and create a TRIGGER for before INSERT, like this:
CREATE TRIGGER set_customer_id BEFORE INSERT on heenaj
FOR EACH ROW
BEGIN
SET NEW.c_id = CONCAT((SELECT IFNULL(MAX(id),0)+1 FROM heenaj),SUBSTRING(NEW.name,1,2),SUBSTRING(NEW.number,1,2));
END/
This way, when you insert you can just ignore c_id and insert like this:
insert into heenaj(name,number)
values ("abcd",9868);
The trigger will handle the setting of c_id for you.
sqlfiddle for TRIGGER
P.S. To create the trigger (in the sqlfiddle), I selected / as my delimiter. You might change that / to $$, since you're setting delimiter as $$.

IF NOT EXISTS in mysql showing syntax error

I am trying to convert this tsql to mysql but showing error need help
CREATE PROCEDURE FormAdd
#formName varchar(MAX)
AS
IF NOT EXISTS(SELECT * FROM tbl_Form WHERE formName=#formName)
BEGIN
INSERT INTO tbl_Form
(formName)
VALUES
(#formName)
SELECT ##identity
END
ELSE
BEGIN
SELECT '-1'
END
mysql
CREATE PROCEDURE FormAdd
(p_formName varchar(500) )
begin
INSERT INTO tbl_Form (formName)
VALUES (p_formName)
where NOT EXISTS(SELECT * FROM tbl_Form WHERE formName=p_formName) ;
SELECT Last_insert_id() as returnvalue ;
SELECT '-1' ;
end
Your attempt was syntactically invalid because logically, an INSERT statement cannot contain a WHERE clause since it does not act on existing rows.
If the purpose is to insert only if the value for p_formname is not already present, then an appropriate step would be to define a unique index on that column first. Then, construct your procedure to attempt the insert and inspect the ROW_COUNT() value to see if one was inserted and act accordingly, returning -1 if not to adapt your existing T-SQL procedure.
First create the unique index on p_formname:
ALTER TABLE tbl_Form ADD UNIQUE KEY `idx_formName` (`formName`);
Then your procedure should use INSERT INTO...ON DUPLICATE KEY UPDATE to attempt to insert the row. Per the documentation, the value of ROW_COUNT() will be 0 if a new row was not inserted or 1 if it was.
CREATE PROCEDURE FormAdd (p_formName varchar(500))
BEGIN
/* Attempt the insert, overwrite with the same value if necessary */
INSERT INTO tbl_Form (formName) VALUES (p_formName) ON DUPLICATE KEY UPDATE formName = p_formName;
/* Return the LAST_INSERT_ID() for a new row and -1 otherwise */
SELECT
CASE
WHEN ROW_COUNT() = 1 THEN LAST_INSERT_ID()
ELSE -1
END AS returnValue;
END

How to write a stored procedure to insert values in multiple tables

How do I write a stored procedure to add a person record with multiple addresses?
It is easy if the person has only one address but I'm not sure how to write a stored procedure to add a person with multiple addresses.
Here is the stored procedure to add a person with one address:
DELIMITER $$
CREATE PROCEDURE `log`.`spAddPerson` (
IN personID INT,
IN personName VARCHAR(100),
IN addressLine1 VARCHAR(45),
IN addressLine2 VARCHAR(45),
IN myCity VARCHAR(45),
IN myState VARCHAR(45),
IN myCountry VARCHAR(45)
)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
END;
START TRANSACTION;
INSERT INTO person VALUES(personID,personName);
-- addressid is automatically generated
INSERT INTO address(Line1, Line2,City,State,Country) VALUES
(addressLine1, addressLine2, myCity,myState, myCountry);
INSERT INTO personAddress(personID, last_insert_id());
COMMIT;
END
The above code works fine. However, I do not know how to handle a person with multiple addresses without writing a separate stored procedure. Is there a simple way to do this?
You cannot pass a variable number of variables to a procedure, nor a non-scalar type.
A possible trick would be building a temporary table with the addresses before calling this procedure. Either the temporary table is pre-determined, or pass its name as a VARCHAR parameter(and use it to build dynamic SQL statements). Eg:
CREATE PROCEDURE spAddPerson (tmp_table VARCHAR(10), ...)
BEGIN
...
PREPARE s AS CONCAT(
'INSERT INTO address (line1, ...) VALUES SELECT * FROM ', tmp_table
);
EXECUTE s;
...
END
-- use it like this
CREATE TEMPORARY TABLE tmp_addresses (line1 VARCHAR(255), ...);
INSERT INTO tmp_addresses VALUES ('1 Cherry Lane'), ... ;
CALL spAddPerson ('tmp_addresses', ...);
However, I would rather split the action in two parts. Do you really want to prevent the creation of the person altogether if its address creation fails? And even then, wouldn't you want to advise your user why the transaction failed (user creation or address creation)?
I would rather treat these two exceptions separately at the application level:
issue a "START TRANSATION"
try to insert a person (call stored proc 1)
if it failed, rollback and notify user
for each address
try to insert an address (call stored proc 2)
if it failed, rollback and notify user
issue a "COMMIT"
> DECLARE #LAST_INSERT_ID INT
> DECLARE #EXECUTION_OK char(1)
> SET #EXECUTION_OK = 1
>
> insert into base_table(imgPath,store,apparelType) values (imgPath,store,apparelType)
>
> SELECT #LAST_INSERT_ID = SCOPE_IDENTITY()
>
> insert into data_table(cvID,color) values (#LAST_INSERT_ID, color)
> GO
>
> If exists( Select cvID from data_table where cvID= #LAST_INSERT_ID)
> Begin
> #EXECUTION_OK = 0
> End