1

ユーザーのアクティブ化が成功したかどうかに応じて、0または1を返すことになっているSQL関数があります。対話する必要がある次の2つのテーブルがあります。

users {user_id, unique email, ...}
user_activation {activation_hash, unique email, ...}

関数は以下を評価することになっています:

  1. 着信ハッシュはuser_activationの行と一致しますか?
  2. また、対応する電子メールはユーザーテーブルにまだ存在していませんか?
  3. 次に、新しいユーザーをユーザーに挿入し、アクティベーション行を削除して1を返します。それ以外の場合は、0を返します。

これが私の関数です:

delimiter #
create function activate_user
(
    p_activation_hash char(32)
)
returns int
deterministic
begin

    if not exists (
        select 1 from users u
        inner join (
            select email from user_activation where activation_hash = p_activation_hash
        ) ua
        on u.email = ua.email
    )
  then

    -- hash exists but email doesnt so add
    insert into users (email, password_hash, first_name, last_name, company_name)
      select email, password_hash, first_name, last_name, company_name
      from user_activation
      where activation_hash = p_activation_hash
      and expiry_date > now();

    -- delete the activation row(s)
    delete low_priority from user_activation where activation_hash = p_activation_hash;

    return 1;

  end if;

  return 0;

end #
delimiter ;

私の問題は、条件が常にtrueと評価されることです(ただし、uniqueキーワードがなくてもユーザーテーブルに挿入される行は1つだけです)。

ありがとう。

4

2 に答える 2

1

その関数の結果は特定の入力に対して毎回同じではないため、定義をからDETERMINISTICに変更してみてくださいNOT DETERMINISTIC(またはデフォルトなので削除してください)。NOT

(有効な)ハッシュが1回使用されると、関数はそのハッシュに対して異なる値を返します。1その関数を最初に呼び出したときに返され、今度はそれを呼び出すたびに、アクティベーションレコードが存在しなくても同じ値を返すため、同じ結果が何度も表示される可能性があります。ハッシュの入力は、ある瞬間は無効で、次の瞬間は有効になる可能性があります(ただし、可能性は低いです)。

詳細については、 CREATEPROCEDURE構文を参照してください。

于 2012-09-11T23:05:28.443 に答える
0

私は今日この問題を再検討し、トリックを実行する非常に便利なNOTINクエリを見つけました。

delimiter #
create procedure activate_user
(
    in p_activation_hash char(32),
    inout status int
)
proc_main:begin

    set status = 0;

    if exists (
        select 1 from user_activation
            where activation_hash = p_activation_hash
            and email not in (select email from users)
    )
    then

    -- hash exists but email doesnt so add
    insert into users (email, password_hash, first_name, last_name, company_name)
      select email, password_hash, first_name, last_name, company_name
      from user_activation
      where activation_hash = p_activation_hash
      and expiry_date > now();

    -- delete the activation row(s)
    delete low_priority from user_activation where activation_hash = p_activation_hash;

    set status = 1;

  end if;

end proc_main #
delimiter ;
于 2012-09-21T22:30:48.620 に答える