1

我有一个 SQL 函数,它应该根据用户激活是否成功返回 0 或 1。我有以下两个需要与之交互的表:

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

该函数应该评估:

  1. 传入的哈希是否与 user_activation 中的一行匹配?
  2. 用户表中是否不存在相应的电子邮件?
  3. 然后在 users 中插入一个新用户并删除激活行并返回 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 ;

我的问题是条件总是评估为真(尽管即使没有唯一关键字,也只有 1 行被插入到用户表中)。

谢谢。

4

2 回答 2

1

尝试将定义从更改DETERMINISTICNOT DETERMINISTIC(或删除它,因为它NOT是默认值),因为对于给定的输入,该函数的结果每次都不相同。

一旦一个(有效的)散列被使用一次,该函数就会为该散列返回一个不同的值。您可能一遍又一遍地看到相同的结果,因为第一次调用该函数时它返回1,而现在每次调用它时它都返回相同的值,即使激活记录不再存在。散列的输入可能在某一时刻无效,然后在下一时刻有效(但不太可能)。

有关详细信息,请参阅CREATE PROCEDURE 语法。

于 2012-09-11T23:05:28.443 回答
0

我今天重新审视了这个问题,发现了一个非常方便的 NOT IN 查询,它可以解决问题:

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 回答