1

ユーザーが存在するかどうかを確認するために、ストアドプロシージャを作成しています。問題は、正しいユーザー名を渡すと正常に実行されますが、間違ったユーザー名を渡すと無限ループが発生することです。

どこが間違っているのですか?これが私のストアドプロシージャです:

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
4

2 に答える 2

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;
于 2013-03-16T14:35:45.427 に答える
0

成功ブランチだけでなく、すべてのブランチのループカウンターをインクリメントし、結果を保持する結果変数を持っていることを確認してください。

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の専門家ではありません)

CREATE PROCEDURE `VerifyUserNPass`(userParam varchar(50), out result int)
BEGIN
 select COUNT(userName) into result from users where username = @userParam
END
于 2013-03-16T13:57:14.343 に答える