MySQL Stored procedure SELECT var wrong value after INSERT - mysql

I have a problem on MySQL stored procedure, already did another logic with IF THEN ELSE, but I still have problems which I cant understand...
The procedure consists on two user inputs: user_id and meet_id. The procedure define a variable called 'ue' which stores result of a bunch of validation (if user exists, if event exists, if event date is still valid, etc.).
After that, it does INSERT and UPDATE some data on multiple tables in IF THEN ELSE selector, and SELECT 1 (or 0) AS result depending of validation.
But my problem is: it always return me 0 as 'result', as if my validation variable was 0 when I do INSERT... And there is where things get weird, if I remove the INSERT [...]; line of the code, it returns me the value of validation correctly (1 or 0).
The code of the procedure is this one:
CREATE DEFINER=`nwouserf`#`localhost`
PROCEDURE `join_event`(IN `user_id` BIGINT(64), IN `event_id` INT)
NOT DETERMINISTIC MODIFIES SQL DATA SQL SECURITY DEFINER
begin
DECLARE ue INT;
SET ue = EXISTS(SELECT 1 FROM users WHERE fb_uid=user_id)
AND EXISTS(SELECT 1 FROM meetup WHERE meet_id=event_id)
AND EXISTS(SELECT 1 FROM meetup WHERE date > NOW() AND meet_id = event_id)
AND EXISTS(SELECT 1 FROM meetup WHERE meet_id = event_id AND participants <= max_participants)
AND NOT EXISTS(SELECT 1 FROM meetup_participation WHERE fb_uid = user_id AND meet_id = event_id);
IF ue = 1 THEN
INSERT INTO meetup_participation (fb_uid, meet_id) VALUES (user_id, event_id);
UPDATE users SET events_participated = events_participated + 1 WHERE fb_uid=user_id;
UPDATE meetup SET participants = participants + 1 WHERE meet_id=event_id;
SELECT 1 AS result;
ELSEIF ue = 0 THEN
SELECT 0 AS result;
ELSE
SELECT null AS result;
END IF;
end
Thanks in advance!
I have been stuck on this for a while now, and can not figure out why.

You should define OUT parameter. Add
", OUT result INT"
immediately after the last IN parameter.

Related

Check condition and send out parameter value from procedure in MySQL

I'm creating a procedure where it needs to check the value of a column IsLoggedIn and send the outparameter with -1 if "IsLoggedIn" is 1 else it needs to send the user information.
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `sp_bh_loginverify1`(IN `user_email` VARCHAR(100), OUT `p_islogged` INT)
NO SQL
BEGIN
IF (EXISTS(select * FROM user_details WHERE user_email = user_email))
THEN
SET p_islogged = 1; SELECT 0;
END IF;
(select UD.user_id, UD.user_name, UD.password, UD.password_salt, UD.user_email, R.role_id as role, R.role_name as role_name from user_details UD
JOIN roles R on R.role_id = UD.role
where (UD.user_email = user_email OR UD.user_name = user_email));
END$$
DELIMITER ;
First of all, always name your procedure input parameters something different from the columns of your table. For example you do this:
IF (EXISTS(select * FROM user_details WHERE user_email = user_email))
How is MySQL supposed to know that user_email is the column in the table, but user_email is the procedure parameter of that name? It doesn't -- it assumes both are references to the column. It compares the column user_email to itself, which will return every row where the column is not NULL, because it's always true that user_email = user_email. In other words, that the column is equal to itself (unless it's NULL).
You shoudl name the procedure parameter something distinct from the column name:
CREATE DEFINER=`root`#`localhost` PROCEDURE `sp_bh_loginverify1`(IN `p_user_email` VARCHAR(100), OUT `p_islogged` INT)
You used NO SQL which means: "indicates that the routine contains no SQL statements." But that's not true, because you do have SQL statement in this procedure.
You should use:
READS SQL DATA
You said you want to return -1 in the OUT parameter, but you set 1. So you should set -1.
Next you mentioned "else it sends user information" which suggests you want that result set to be returned only conditionally. But your code returns that user information outside the IF/END IF block, so it happens regardless of the condition. You should use an ELSE block to do this.
Notice the use of p_user_email in the queries below, to make it distinct from user_email.
BEGIN
IF (EXISTS(select * FROM user_details WHERE user_email = p_user_email))
THEN
SET p_islogged = -1;
ELSE
SELECT UD.user_id, UD.user_name, UD.password, UD.password_salt, UD.user_email,
R.role_id as role, R.role_name as role_name
FROM user_details UD
JOIN roles R ON R.role_id = UD.role
WHERE UD.user_email = p_user_email OR UD.user_name = p_user_email;
END IF;
END
I don't think you need SELECT 0; at all. MySQL stored procedures can return no result set, or one result set, or multiple result sets.

MySQL procedure returning wrong value (INSERT SELECT confronting)

I'm completely new to MySQL, and have been bumping with some errors, but always I do find solutions, except for this one I can't understand how to get around it.
The following MySQL Procedure returns me a value if variable "ue" is 1 or 0 (a bunch of exists validation). The validation part (SET ue = EXISTS...) works without the rest of the code, as it should, the problem is not there. But when I do execute the command INSERT INTO SELECT, it does not work, it always return 0 as response, when it should be 1. These two lines are getting in confrontation with each other.
INSERT INTO meetup_participation SELECT user_id, event_id FROM DUAL WHERE ue=1;
SELECT ue AS response;
The procedure should add 'user id' and 'event id' into meetup_participation, and then update the row at 'users' corresponding to the user with that 'user id' to increment the 'events participated'. And it also UPDATE to increment the participation in the event with this 'event id'.
I am using the SET ue to validate things like, if user exists, if event does exists, if date of event is still valid, and if user is not already in this table. So I am passing this value as a boolean to INSERT INTO meetup_participation [...] WHERE ue = 1. After that, I do SELECT ue to inform validation returned true and procedure executed without problems.
Here is the full procedure.
CREATE DEFINER=`user`#`localhost` PROCEDURE `join_event`(IN `user_id` BIGINT(64), IN `event_id` INT) NOT DETERMINISTIC MODIFIES SQL DATA SQL SECURITY DEFINER
begin
DECLARE ue INT;
SET ue = EXISTS(SELECT 1 FROM users WHERE fb_uid=user_id) AND EXISTS(SELECT 1 FROM meetup WHERE meet_id=event_id) AND EXISTS(SELECT 1 FROM meetup WHERE date > NOW() AND meet_id = event_id) AND EXISTS(SELECT 1 FROM meetup WHERE meet_id = event_id AND participants <= max_participants) AND NOT EXISTS(SELECT 1 FROM meetup_participation WHERE fb_uid = user_id AND meet_id = event_id);
INSERT INTO meetup_participation SELECT user_id, event_id FROM DUAL WHERE ue=1;
UPDATE users SET events_participated = events_participated + 1 WHERE fb_uid=user_id AND ue=1;
UPDATE meetup SET participants = participants + 1 WHERE meet_id=event_id AND ue=1;
SELECT ue AS response;
end
Thanks in advance.
The INSERT statement is executed separately from the SET ue =... statement. I'm not sure what you are trying to accomplish, but the code makes no sense.
If you want to add records to meetup_participation based on the EXISTS tests applied to each record in the users table, you would need to apply the tests to each record in your SELECT statement as part of the INSERT.
There are also numerous syntax/grammar issues in the code as shown.
If you could provide an explanation of what you are trying to accomplish with the procedure, that might allow someone to suggest the right way to code the procedure.
Selecting ue will not tell you if the procedure completed without error. You should research mysql transactions and mysql error handling. http://www.mysqltutorial.org/mysql-error-handling-in-stored-procedures/ is a good starting point.
You might end up with something like this
drop procedure if exists p;
delimiter //
CREATE DEFINER=`root`#`localhost` PROCEDURE `p`(
IN `inue` int,
IN `user_id` BIGINT(64),
IN `event_id` INT
)
LANGUAGE SQL
NOT DETERMINISTIC
MODIFIES SQL DATA
SQL SECURITY DEFINER
COMMENT ''
begin
DECLARE ue INT;
declare exit handler for sqlexception
begin
rollback;
insert into errors (msg) select concat('error ' ,inue,',',user_id,',',event_id);
end;
set autocommit = 0;
#set ue = inue;
SET ue = EXISTS(SELECT 1 FROM users WHERE fb_uid=user_id)
AND EXISTS(SELECT 1 FROM meetup WHERE meet_id=event_id)
#AND EXISTS(SELECT 1 FROM meetup WHERE dt > NOW() AND meet_id = event_id)
AND EXISTS(SELECT 1 FROM meetup WHERE meet_id = event_id AND ifnull(participants,0) <= max_participants)
AND NOT EXISTS(SELECT 1 FROM meetup_participation WHERE fb_uid = user_id AND meet_id = event_id)
;
select ue;
if ue = 1 then
start transaction;
INSERT INTO meetup_participation SELECT user_id, event_id,user_id, event_id;
UPDATE users SET events_participated = ifnull(events_participated,0) + 1 WHERE fb_uid=user_id = user_id;
UPDATE meetup SET participants = ifnull(participants,0) + 1 WHERE meet_id = event_id ;
commit;
end if;
SELECT ue AS response;
end //
The error table looks like this
CREATE TABLE `errors` (
`msg` varchar(2000) DEFAULT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
Note I am not suggesting this is a solution appropriate to your site , you need to do the research and figure out what is best for you.

change one table data when single column all data of another table is equal to some value in mysql

I have created 2 tables named snag_list and defect_list. I need to change the status field of snag_list to 2 when all the defect_list status should to be 2
Not sure if this helps but try to create a trigger for defect_list
and check the distinct count of status column if it is one and the value is 2 then update the snag_list a example would look like this
DELIMITER $$
CREATE TRIGGER checkstatus
AFTER UPDATE ON defect_list
FOR EACH ROW
BEGIN
DECLARE cnt INT
SELECT COUNT(DISTINCT status) FROM defect_list INTO cnt
DECLARE st INT
SELECT DISTINCT status FROM defect_list LIMIT 1 INTO st
IF(cnt = 1 AND st = 2)
UPDATE snag_list SET status = 2
ENF IF
END$$
DELIMITER ;
Your question is very vague but I guess this is what you may be looking for.
DECLARE
count_rec VARCHAR2(10);
data_rec VARCHAR2(10);
BEGIN
SELECT COUNT(DISTINCT status) INTO count_rec FROM defect_list;
SELECT DISTINCT status INTO data_rec FROM defect_list;
IF (count_rec = '1' AND data_rec = '2') THEN
UPDATE snag_list SET status = '2';
END IF;
END;
edit -> You can change the datatype of the 2 variables as required. Go with VARCHAR2 if you're unsure whether the data would be numeric.

MySQL procedure gone wrong

I have a MySQL database in which I have the following rows (by exemple) created by default (id, task and case may be different but the current value is always 1)
....idtaskcaseuser............datecurrent
238......31001.....0..............null..........1
239......41001.....0..............null..........1
I have to randomly create rows like this with insert statement (new rows). As you can see a date is filled and de current equal 0
....idtaskcaseuser............datecurrent
240......51001.....12015.04.03..........0
241......21002.....12015.04.03..........0
When I come across one of the lines created by default I want to use an update instead of an insert statement.
So I created the following procedure in MySQL
DELIMITER //
DROP PROCEDURE IF EXISTS FillProgress//
CREATE PROCEDURE FillProgress ( get_case INT(10),get_task INT(10), get_user INT(10) )
BEGIN
DECLARE test tinyint(1);
SET test = (SELECT COUNT(*) FROM progress WHERE case_id = get_case AND task_id = get_task);
IF test = 1 THEN
UPDATE progress SET current = 0, date = NOW(), user_id = get_user WHERE task_id = get_id AND case_id = get_case;
ELSE
INSERT INTO progress(task_id,case_id,user_id,date,current) VALUES (get_task,get_case,get_user,NOW(),0);
END IF;
END; //
DELIMITER ;
I use count to see if a already have a row with the same case and task. If it's true (test=1) I use UPDATE, otherwise and use INSERT.
If I test with the following row already wrote in the database
....idtaskcaseuserdatecurrent
241......41001.....0..null..........1
I use CALL FillProgress(1001,4,1);
The row is not updated, but I do not have any error message.
11:38:02 CALL FillProgress(1001,4,1) 0 row(s) affected 0.000 sec
And if I manually use my update query
UPDATE progress SET current = 0, date = NOW(), user_id = 1 WHERE task_id = 4 AND case_id = 1001;
It works like a charm.
The insert query also works fine.
The UPDATE query within the procedure has a "WHERE task_id = get_id" clause, however I don't see get_id being defined in the procedure; there is a "get_task" parameter for the stored procedure, though.

No data return after calling the stored procedures with multiple cursors in it

I have a stored procedures with the following code. The reason i use cursor is to join table which something will return NULL value and cause the record to be disappear. By using this method, I am able to get all data without losing any.
The only problem now is that when i try to call the stored precedures, it return
Error Code : 1329
No data - zero rows fetched, selected, or processed
but when i do a manual select * from TMOMain, the table is created and there is data in it but no data from SignUpCur and UnSubCur mean it was not updated.
1st time using mysql stored procedures so there might be something i miss out.
My Code
ROOT:BEGIN
DECLARE pTotal,pShortCode,pSignUp,pUnSub,pJunk,pT INT;
DECLARE pTc NVARCHAR(10);
DECLARE SignTotal,UnSubTotal, JunkTotal INT;
DECLARE pSignTotal,pSignTeamID,pUnSubTotal,pUnSubT,pSignUpS,pUnSubS INT;
DECLARE pSignTeam,pUnSubTeam NVARCHAR(10);
DECLARE no_more_rows BOOLEAN;
DECLARE MoMainCur CURSOR FOR
SELECT COUNT(*) AS GrandTotal,pShort,(CASE WHEN r= 1 THEN 'A'
WHEN r= 2 THEN 'B' WHEN r= 3 THEN 'C' ELSE 'UV' END) AS Team,recvTeamID
FROM tbli
INNER JOIN tblK ON keywordid = rkey
WHERE recvDate >='2011-11-15' AND recvDate < '2011-11-16'
GROUP BY pShort,Team,recvTeamID;
DECLARE SignUpCur CURSOR FOR
SELECT COUNT(*) AS SignUp,(CASE WHEN r= 1 THEN 'A'
WHEN r= 2 THEN 'B' WHEN r= 3 THEN 'C' ELSE 'UV' END) AS Team,
recvTeamID,pShort
FROM tbli INNER JOIN tbl_user ON recvphone = userphone
INNER JOIN tblK ON keywordid = userpublicstatus
WHERE userdatejoined >='2011-11-15' AND userdatejoined < '2011-11-16'
AND recvdate >='2011-11-15' AND recvdate < '2011-11-16'
GROUP BY Team,recvTeamID,pShort;
DECLARE UnSubCur CURSOR FOR
SELECT COUNT(*) AS UnSub,(CASE WHEN r= 1 THEN 'A'
WHEN r= 2 THEN 'B' WHEN r= 3 THEN 'C' ELSE 'UV' END) AS Team,
recvTeamID,pShort
FROM tbliINNER JOIN tbl_user ON recvphone = userphone
INNER JOIN tblK ON keywordid = userpublicstatus
WHERE userdateExpire >='2011-11-15' AND userdateExpire <'2011-11-16'
AND recvdate >='2011-11-15' AND recvdate < '2011-11-16'
GROUP BY Team,recvTeamID,pShort;
DROP TABLE IF EXISTS `TMoMain`;
CREATE TEMPORARY TABLE TMOMain
(GrandTotal INT,ShortCode INT,Team NVARCHAR(10),SignUp INT,UnSub INT, Junk INT, TeamID INT);
OPEN MoMainCur;
-- Main Table
read_loop:LOOP
FETCH MoMainCur INTO pTotal,pShortCode,pTc,pT;
INSERT INTO TMOMain
VALUES
(pTotal,pShortcode,pTc,0,0,0,pT);
END LOOP read_loop;
CLOSE MoMainCur;
-- Insert Signup Details into Main Table
OPEN SignUpCur;
SignUp_Loop:LOOP
FETCH SignUpCur INTO pSignTotal,pSignTeam,pSignTeamID,pSignUpS;
UPDATE TMOMain
SET SignUp = pSignTotal
WHERE Team = pSignTeam AND Shortcode =pSignUpS;
END LOOP SignUp_Loop;
CLOSE SignUpCur;
-- Insert UnSub Details into Main Table
OPEN UnSubCur;
UnSub_Loop:LOOP
FETCH UnSubCur INTO pUnSubTotal,pUnSubTeam,pUnSubT,pUnSubS;
UPDATE TMOMain
SET UnSub = pSignTotal
WHERE Team = pUnSubTeam AND pShort = pUnSubShortCode;
END LOOP UnSub_Loop;
CLOSE UnSubCur;
SELECT * FROM TMOMain;
END$$
Please try this out:
Add this declaration once (at the top):
DECLARE curIsDone INT DEFAULT FALSE;
Then after you declare your cursor add this:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET curIsDone = TRUE;
After your FETCH commands and before the actions you intend to perform:
IF curIsDone THEN
LEAVE read_loop;
END IF;