test a stored procedure in MySql Workbench - mysql

I have an Insert stored procedure where I am inserting into 2 tables. The second table using the Last_Insert_ID of the first table. Here is my sproc:
DELIMITER $$
CREATE DEFINER=`root`#`%` PROCEDURE `new_user_create`(
IN oFarmName varchar(45),
IN oFirstName varchar(45),
IN oAddress1 varchar(45),
IN oCity varchar(45),
IN oState varchar(45),
IN oZip varchar(45),
IN oCountry varchar(45)
)
BEGIN
insert into intelliair.individual
( FarmName, FirstName)
values ( oFarmName, oFirstName);
insert into intelliair.address
(IndividualID, Address1, City, State, Zip, Country)
Values (Last_Insert_ID(), oAddress1, oCity, oState, oZip, oCountry);
END
Here is how I am testing the query in MySql workbench:
call new_user_create(#myFarm, #MyName, #MyAddress, #MyCity, #MyState, #MyZip, #MyCountry)
There error I get is: "Column Address1 cannot be null"
Where am I going wronng? Is it in the sproc? Or the way I am calling it?

"Column Address1 cannot be null" indicates that the intelliair.address.Address1 field must be defined not null.
And, I don't think that you pre defined value for #MyAddress before passing it to the stored procedure.
Unless defined it is treated as NULL and hence is the error thrown.
To cross check values before calling the stored procedure like :
select #MyAddress; -- ,#myFarm, #MyName, #MyCity, #MyState, #MyZip, #MyCountry;
Update 1:
You can call stored procedure by directly inputting values for each of the parameters.
Example:
call new_user_create(
'my Farm value', -- #myFarm
'E B', -- #MyName
'My Address is SO', -- #MyAddress1
'My City is Coders', -- #MyCity
'CA', -- #MyState
'12345', -- #MyZip
'US' -- #MyCountry
);

The exception is being thrown by an INSERT (or UPDATE) statement, that is assigning a NULL value to a column named Address1 that is declared to be NOT NULL.
The most likely explanation, from what you show, is that the value passed in as the oAddress1 parameter is NULL, and the exception is being thrown by the second INSERT statement.
The most likely explanation, therefore, is that when the call to the procedure is made, the #MyAddress user variable is not assigned a value.
(You can verify there is not an Address1 column on the intelliair.individual table, or that if there is one, it's not defined as NOT NULL.)
(There's also a possibility that it's not one of your statements that's throwing the exception, but rather a recursive SQL statement, like an INSERT statement in a BEFORE INSERT FOR EACH ROW trigger.)

USE lportal;
DELIMITER $$
CREATE PROCEDURE `iemp`(IN eid INT(11),IN ename varchar(15),IN dname varchar(15),IN doj DATE)
BEGIN
INSERT INTO e_emp (eid,ename,dname,doj) VALUES (eid,ename,dname,doj);
END

Related

Stored Procedure with both IN and OUT, with OUT parameter being the last_insert_id() fails

I have this MYSQL Stored procedure that will insert a record and I need the output to give the last_insert_id(). I have tried several different commands, (listed below the procedure) to get this number, but nothing works.
here is the stored procedure:
CREATE DEFINER=`root`#`%` PROCEDURE `TestInsert`(IN v_area_id INT, IN v_regid INT, IN v_event INT, IN v_familyid INT, IN v_memberid INT, IN v_amount DECIMAL(12,2),
IN v_desc varchar(255), OUT auto_id INTEGER )
BEGIN
DECLARE auto_id INT DEFAULT 0;
INSERT INTO stripe (area_id, regid, event, familyid, memberid, totalamt, charge_description)
values (v_area_id, v_regid, v_event, v_familyid, v_memberid, v_amount, v_desc);
SET #auto_id = LAST_INSERT_ID();
END
I have tried these different commands to get a result:
SET auto_id := last_insert_id();
SELECT last_insert_id() INTO #auto_id; (also without the #)
Using or not using the "DECLARE auto_id INT DEFAULT 0;" makes no difference.
Also found some other commands here stack overflow, which I don't remember now.
the Insert works fine, just can't get the id.
I'm using Navicat command console.

MySQL PROCEDURE using IF Statement with #Parameter Not Working

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.

function that returns a table sql

I have this function:
DROP FUNCTION IF EXISTS MinCarAltezza;
DELIMITER $$
CREATE FUNCTION MinCarAltezza(altezza INT)
RETURNS SchedaTab TABLE(
Nome varchar(64),
Cognome varchar(64),
ID_Scheda int(10),
Sequenza int(2),
nSerie int(2),
nRipetizioni int(2),
Carico_Minimo decimal(4,1),
Esercizio varchar(30),
PRIMARY KEY(Nome,Cognome,Esercizio)
)
AS BEGIN
INSERT SchedaTab
SELECT DISTINCT U.Nome,U.Cognome,P.ID_Scheda,P.Sequenza,P.nSerie,
P.nRipetizioni,MIN(P.Carico),P.Esercizio
FROM utente AS U, scheda AS S, programma AS P
WHERE U.CF=S.ID_Utente AND S.ID_Scheda=P.ID_Scheda AND U.Altezza>altezza
AND P.Carico<>0
AND S.ID_Ist NOT IN(SELECT CF FROM istruttore WHERE Stipendio>500)
GROUP BY U.Nome,U.Cognome,S.ID_Scheda
RETURN
END $$
DELIMITER ;
that gives me an error in the line 4 where I declare the return type TABLE.
Is there something I'm missing?
That's the db if someone needs it: http://pastebin.com/DWYqVBpa
thank you
In MySQL there is no "table" data type, hence the error message. As MySQL documentation on stored functions says, return value can be
Any valid MySQL data type
Therefore, a stored function cannot return with a table. I would change the function into a stored procedure and
have a select statement at the end of the procedure (MySQL return the result of the last select)
or create a temporary table with the data and return the name of the temporary table in an out parameter

How to select into a variable in SQL when the result might be null?

I have the following stored procedure:
DELIMITER //
CREATE PROCEDURE NewSeqType(IN mySubschemaID INT, IN hashVal bigint(20))
BEGIN
DECLARE newSeqTypeID INT;
SELECT MAX(ID)+1 INTO newSeqTypeID FROM sequenceType WHERE subschemaID=mySubschemaID;
INSERT INTO SequenceType(ID, HashValue, subschemaID) VALUES(newSeqTypeID, hashVal, mySubschemaID);
SELECT LAST_INSERT_ID() as ID; -- return prim key
END//
This works when there is already data in the table where subschemaID=mySubschemaID, but if that SELECT statement returns null, then the MAX(ID)+1 part gives the error column ID cannot be null.
How can I give ID a default value, say 0, in that case?
For this, you can use coalesce():
SELECT coalesce(MAX(ID)+1, 1) INTO newSeqTypeID FROM sequenceType WHERE subschemaID=mySubschemaID;
INSERT INTO SequenceType(ID, HashValue, subschemaID) VALUES(newSeqTypeID, hashVal, mySubschemaID);
Often, this type of work is done in a before insert trigger, to keep the values aligned.

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