【问题标题】:How do I get the next open number?如何获得下一个开放号码?
【发布时间】:2014-12-22 23:10:23
【问题描述】:

我有一个如下所示的 SQL 列。

注意 1100 和 2000 中的数字(1101 - 1123 不显示,但它们存在)。我编写了一个脚本来制作它,以便在某个组注册的用户将获得与该组对应的登录名。因此,如果他们在基本组中注册,他们将获得 1100 年代的第一个可用登录名。如果他们在中等组中注册,那么他们将在 2000 年代获得第一个可用的登录名。假设用户 AAL2002 被删除,下一个加入的人应该登录 2002,而不是 2007(以便自动填补空白)。

现在我有一个 PHP 脚本,它试图查看所有内容并为他们提供一个新的、未使用的登录名。问题是它重复了一些登录。有没有其他方法可以用 PHP 和 SQL 做到这一点?

如果您认为可以修复,这是我可怕的、令人困惑的代码:

$husers = Query::runQuery("SELECT * FROM `users` WHERE `group`=? AND `login` NOT BETWEEN 'AAL1000' AND 'AAL1010'", array($post['group']));
            $i = 0;
            $f = false;
            do
            {
                $baseid = (substr($users[$i]['login'], 3)) + 1;

                if($baseid != substr($users[$i+1]['login'], 3))
                {
                    $checkid = Query::runQuery("SELECT * FROM `users` WHERE `login`=?", array("AAL".$baseid));

                    if($checkid[0]['login'] != "AAL".$baseid)
                    {
                        $f = true;
                    }

                }

                $i++;
            }

【问题讨论】:

  • 如果你在 INTEGER 列中有数字会更容易。
  • @Barmar 这是问题的一部分。
  • 给出的两个答案都没有帮助我。

标签: php mysql sql


【解决方案1】:

如果您有多个用户同时注册(竞争条件),这将根本不起作用。您可以通过使用数据库事务来解决这个问题。 最重要的是,您应该使用 SQL 函数为您的用户查找并注册下一个免费 ID。与事务一起,这将为您提供一种解决方案,即使您的脚本一次被多个人调用,也同样有效。

在 mysql 中,通常只使用自增列来避免此类问题。在大多数其他数据库上,如果您不使用连续整数列,则必须走上艰难的道路。

【讨论】:

  • 事务没有帮助。只需使列独一无二。
  • 如果两个脚本同时运行并且碰巧获得相同的 ID,他仍然会覆盖用户。这就是需要锁定的原因,最简单的方法是使用事务。
  • 1) 你不能用insert 覆盖。 2)交易不能解决问题。如果你想要锁定,你需要锁定。
【解决方案2】:

鉴于:

CREATE TABLE login (
    login VARCHAR(4)
);

INSERT INTO login (login) 
    VALUES ('1100'), ('1101'), ('1102'), ('1106'), ('1107');

查询:

SELECT MIN(login) + 1 AS result FROM (
    SELECT login,
        (SELECT MIN(l2.login) FROM login l2 WHERE l2.login = l.login + 1) AS next
    FROM login l
    HAVING next IS NULL
) AS list;

给出以下结果:

+--------+
| result |
+--------+
|   1103 |
+--------+

我的示例仅使用 alpha + decimal 字段的整数部分。这让我不必做substring operations,基于前缀(“AAL11”,“AAL20”)和最终的强制转换(也许没有必要,因为我用 varchar 演示)但仍然显示了它是如何时间>完成。我把它留作练习。

如前所述,您只能同时运行查找 + 插入操作。这意味着您需要将其作为应用程序中的原子操作(通常称为事务,但我不是指 SQL 事务)。

【讨论】:

  • 我对SQL不是很精通,但我猜应该是这样的吧? SELECT MIN(SUBSTRING(login, 3, 4)) + 1 作为结果 FROM (SELECT SUBSTRING(login, 3, 4), (SELECT MIN(SUBSTRING(l2.login, 3, 4)) FROM SUBSTRING(login, 3, 4) l2 WHERE SUBSTRING(l2.login , 3, 4) = SUBSTRING(l.login , 3, 4) + 1) AS next FROM SUBSTRING(login , 3, 4) l HAVING next IS NULL ) AS 列表
  • 另外,我不知道如何根据前缀进行分组。
  • @Karoly Horvath:我不是指 SQL 事务,我指的是应用程序级别的事务。也许应该写原子操作。
猜你喜欢
  • 2022-01-10
  • 1970-01-01
  • 2014-06-11
  • 2021-02-28
  • 2010-10-17
  • 1970-01-01
  • 1970-01-01
  • 2021-11-29
  • 2021-12-04
相关资源
最近更新 更多