我正在制作存储过程以检查用户是否存在。问题是每当我传递正确的用户名时,它就会成功执行但是当我传递错误的用户名时,它会经历一个无限循环。
我哪里错了?这是我的存储过程:
CREATE PROCEDURE `VerifyUserNPass`(userParam varchar(50), out result int)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tempUser varchar(50) default '';
DECLARE count int default 0;
DECLARE noRows int;
DECLARE userList cursor for select userName from users;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
select count(*) into noRows from users;
OPEN userList;
read_loop: LOOP
FETCH userList into tempUser;
IF tempUser = userParam THEN
SET @count = count + 1;
LEAVE read_loop;
ELSEIF count > noRows THEN
LEAVE read_loop;
END IF;
END LOOP;
CLOSE userList;
select count into result;
END
答案 0 :(得分:1)
要修复代码,请对done
变量使用条件测试来确定是否退出循环。 (done
变量初始化为FALSE,然后在没有更多行的情况下在CONTINUE HANDLER中设置为TRUE。)
删除查询“count(*)
”查询和noRows
变量;那些是不需要的。 (在并发系统中,count(*)查询可能返回一个与以后查询返回的行数不同的值。(考虑到其他会话在程序运行时插入或删除行的可能性) 。)
还要删除对@count
用户变量的引用。对于用户变量@coount
和过程变量count
,您有多种引用。这些是自变量。您的过程无需使用用户变量。相反,坚持使用在您的过程中声明的变量。 (在需要时保存用户变量。)
-- select count(*) into noRows from users;
read_loop: LOOP
FETCH userList into tempUser;
IF done THEN
LEAVE read_loop;
END IF;
IF tempUser = userParam THEN
SET count = 1;
LEAVE read_loop;
END IF;
END LOOP;
一种更有效的代码编写方法是让数据库通过在查询中添加WHERE子句来查找您感兴趣的行。 (您无需获取与您感兴趣的条件不匹配的行。)
修改游标定义以包含谓词(即WHERE子句中的条件)以限制返回的行:
DECLARE userList cursor for select userName from users
WHERE userName = userParam LIMIT 1;
我不明白这里需要一个程序。本机SQL语句会更有效,例如。
SELECT 1 AS found FROM users u WHERE u.userName = 'foo' LIMIT 1;
答案 1 :(得分:0)
确保不仅在succes分支中增加所有分支的循环计数器,并使用结果变量来保存结果。
DECLARE userFound int default 0;
......
read_loop: LOOP
FETCH userList into tempUser;
SET @count = @count + 1;
IF tempUser = userParam THEN
SET @userFound = 1
LEAVE read_loop;
ELSEIF count > noRows THEN
LEAVE read_loop;
END IF;
.....
select userFound into result;
我希望这会返回相同的结果(但我不是MySql expert)
CREATE PROCEDURE `VerifyUserNPass`(userParam varchar(50), out result int)
BEGIN
select COUNT(userName) into result from users where username = @userParam
END