【问题标题】:How to Generate Random number without repeat in database using PHP?如何使用 PHP 在数据库中生成随机数而不重复?
【发布时间】:2012-07-25 16:08:55
【问题描述】:

我想生成一个在数据库中不重复的 5 位数字。 假设我有一个名为 numbers_mst 的表,其中的字段名为 my_number

我想以在 my_number 字段中不重复的方式生成数字。 并且前面的零是允许的。所以像 00001 这样的数字是允许的。 另一件事是它应该在 00001 到 99999 之间。我该怎么做?

我可以在这里猜到的一件事是我可能必须创建一个递归函数来将数字检查到表中并生成。

【问题讨论】:

  • 如果允许前面的零,它们是强制性的吗? 01 和 001 有区别吗?
  • 我需要 5 位数字,或者你只能说 5 位字符串。所以01或001没有机会来了:)
  • 唯一编号用完会怎样? ;)
  • 这不会发生,这就是为什么我选择了 99999 的限制 :) 即使达到 9999,这对我来说也是太多的记录
  • @aslamdoctor 您在此问题中接受的答案不正确,因为在 where 子句中,它尝试将字符串“random_num”与数字列表匹配。您真的应该不接受并从答案中删除任何正面评论。

标签: mysql


【解决方案1】:
  1. 生成随机数。

  2. 检查随机数是否在数据库中。

  3. 如果没有,请停止,使用此号码。

  4. 转到步骤 1。

【讨论】:

    【解决方案2】:
    SELECT FLOOR(RAND() * 99999) AS random_num
    FROM numbers_mst 
    WHERE "random_num" NOT IN (SELECT my_number FROM numbers_mst)
    LIMIT 1
    

    这是做什么的:

    1. 使用 RAND() 选择 0 - 1 之间的随机数。
    2. 将其放大为 0 - 99999 之间的数字。
    3. 只选择表中不存在的那些。
    4. 仅返回 1 个结果。

    【讨论】:

    • 非常好,虽然随着选项开始用完可能会很慢,预加载具有所有可能值的另一个表并从中选择由 rand() 排序的表可能会更快,然后删除所选记录以便它可以永远不会再被选中。
    • 这不像你想象的那样工作。在 where 子句中,它检查字符串“random_num”是否不在子查询的返回列表中......总是如此,因为 my_number 是数字。所以请:这不是您正在寻找的解决方案;)
    • 它不工作,请检查这个例子 SELECT FLOOR(RAND() * 9) AS random_num FROM some_table WHERE "random_num" NOT IN (1,2,3,4,5,6,7 ,9) 限制 1
    • "random_num" 是字符串而不是列名。
    • 这个答案是不正确的,应该被删除,因为它在 where 子句中检查,如果字符串“random_num”不在子查询的返回列表中。
    【解决方案3】:

    你有两种方法:

    在其他答案中建议的第一个是创建一个随机数(使用 mt_rand() )并检查它不在数据库中。如果它在数据库中,请重新生成并重试。如果您要生成一个数字,这是最简单的 - 请参阅代码的其他答案。但是,如果您生成超过 50% 的数字,将会非常缓慢且效率低下。

    如果您想要很多数字,另一种方法是使用所有记录填充数据库并“选择”一列。运行查询以查找“未选择”的数量,然后找到介于 0 和“未选择”的数字之间的随机数。然后运行 ​​SQL 查询以获取该位置的数字(未选择的位置,在 mysql 中使用 LIMIT)并标记为已选择。有点复杂,如果你只想要几个数字,它会做更多的工作并且效率更低,但是当你想要获得超过 50%(估计)的数字时会更好。

    注意:您可以通过在本地存储选择的计数并减少运行一些查询来提高效率。

    【讨论】:

    • 您可以通过从表中删除记录来优化第二个。因此,用序列号预先填充一个表格,然后在随机选择它们时简单地删除它们。
    • 确实如此。但是,我经常发现我想要记录为哪个用户选择了哪个号码,或者哪个活动,或者在什么日期,或者类似的东西。 (我坚信保留日志/可追溯性/跟踪所有内容,这意味着很少删除任何内容,而是经常添加。对于随机抽奖(无论如何我住的地方)这是法律要求。取决于工作。)
    【解决方案4】:

    除了 Tushar 在 numbers_mst 为空时使其工作的答案:

    SELECT random_num
    FROM (
      SELECT FLOOR(RAND() * 99999) AS random_num 
      UNION
      SELECT FLOOR(RAND() * 99999) AS random_num
    ) AS numbers_mst_plus_1
    WHERE `random_num` NOT IN (SELECT my_number FROM numbers_mst)
    LIMIT 1
    

    【讨论】:

    • 在我使用其他答案的那一刻,我发现了这个问题。非常感谢您对此的回答。超级有用
    • 这不适用于所有配置。这是一个新的解决方案:stackoverflow.com/a/40549385/963901
    • 这在某些情况下没有结果
    【解决方案5】:

    这是构建唯一代码生成器而无需检查数据库的最简单方法,它将节省数据库查询执行时间。

    function unique_code_generator($prefix='',$post_fix='')
        {
            $t=time();
            return ( rand(000,111).$prefix.$t.$post_fix);
        }
    

    享受吧,祝你编码愉快..

    :)

    【讨论】:

    • 我喜欢这个,这很简单,但是如果两个用户同时这样做,111 有一个机会会失败,所以你可能需要增加随机数。 :)
    • 是的,我同意你的看法。
    • 如果出现夏令时问题会怎样?
    • 谢谢你的注意,你可以试试 return (rand(000,111).$prefix.$t.$post_fix);带回报 ( rand(000,999).$prefix.$t.$post_fix);
    【解决方案6】:

    注意:发布的其他解决方案仅在列配置为NOT NULL 时才有效。如果NULL,它将不返回任何结果。您可以像这样修复查询:

    SELECT random_num
    FROM (
      SELECT FLOOR(RAND() * 99999) AS random_num
    ) AS numbers_mst_plus_1
    WHERE random_num NOT IN (SELECT my_number FROM numbers_mst WHERE my_number IS NOT NULL)
    LIMIT 1
    

    ... ...WHERE my_number IS NOT NULL 是必须的!

    编辑:我只是想提一下,我故意删除了内部 SELECT 的表名,因为它似乎没有必要,而且如果表中还没有数据,它似乎会中断?但是,也许这是故意包括在内的? ——请为大家澄清或评论,谢谢。

    【讨论】:

    • Your's 在能够实际抓取未使用的随机数方面效果很好。但是,请尝试使用小型数据集。如果选择的 rand 存在,则不返回任何内容。
    【解决方案7】:

    我知道我的回答迟了,但如果有人在未来寻找这个主题,想要一个前导零的随机数,你应该添加LPAD() 函数。

    所以你的查询会喜欢

    SELECT LPAD(FLOOR(RAND()*99999),5,0)
    

    祝你有美好的一天。

    【讨论】:

      【解决方案8】:

      以下查询生成从 0 到 99,999 的所有 int,查找目标表中未使用的值并随机输出这些空闲数之一:

      SELECT random_num FROM (
          select a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a) + (10000 * e.a) as random_num
          from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
          cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
          cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
          cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d
          cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as e
      ) q
      WHERE random_num NOT IN(SELECT my_number FROM numbers_mst)
      ORDER BY RAND() LIMIT 1
      

      好的,它长、慢且不可扩展,但它可以作为独立查询!您可以添加一个删除更多的“0”(连接a、b、c、d、e)来增加或减少范围。

      例如,您还可以使用这种行生成器技术来创建包含所有日期的行。

      【讨论】:

        【解决方案9】:
        DELIMITER $$
        
        USE `temp` $$
        
        DROP PROCEDURE IF EXISTS `GenerateUniqueValue`$$
        
        CREATE PROCEDURE `GenerateUniqueValue`(IN tableName VARCHAR(255),IN columnName VARCHAR(255)) 
        BEGIN
            DECLARE uniqueValue VARCHAR(8) DEFAULT "";
            DECLARE newUniqueValue VARCHAR(8) DEFAULT "";
            WHILE LENGTH(uniqueValue) = 0 DO
                SELECT CONCAT(SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                        SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                        SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                        SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                        SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                        SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                        SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                        SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1)
                        ) INTO @newUniqueValue;
                SET @rcount = -1;
                SET @query=CONCAT('SELECT COUNT(*) INTO @rcount FROM  ',tableName,' WHERE ',columnName,'  like ''',newUniqueValue,'''');
                PREPARE stmt FROM  @query;
                EXECUTE stmt;
                DEALLOCATE PREPARE stmt;
            IF @rcount = 0 THEN
                    SET uniqueValue = @newUniqueValue ;
                END IF ;
            END WHILE ;
            SELECT uniqueValue;
            END$$
        
        DELIMITER ;
        

        使用此存储过程,您可以将其与动态值一起使用,例如

        call GenerateUniqueValue('tablename', 'columnName')
        

        【讨论】:

          【解决方案10】:

          我们可以简单地这样做:

          $regenerateNumber = true;
          
          do {
              $regNum      = rand(2200000, 2299999);
              $checkRegNum = "SELECT * FROM teachers WHERE teacherRegNum = '$regNum'";
              $result      = mysqli_query($connection, $checkRegNum);
          
              if (mysqli_num_rows($result) == 0) {
                  $regenerateNumber = false;
              }
          } while ($regenerateNumber);
          

          $regNum 将具有数据库中不存在的值

          【讨论】:

            【解决方案11】:

            很简单,我在那个存储过程中做了MySQL中的代码

            它生成8位随机数,并且与数据库中的表唯一。

            它对我有用。

            CREATE DEFINER=`pro`@`%` PROCEDURE `get_rand`()
            BEGIN
            DECLARE regenerateNumber BOOLEAN default true;
            declare regNum int;
            declare cn varchar(255);
            repeat
            SET regNum      := FLOOR(RAND()*90000000+10000000);
            SET cn =(SELECT count(*) FROM stock WHERE id = regNum);
            select regNum;
            if cn=0
            then
            SET regenerateNumber = false;
            end if;
            UNTIL regenerateNumber=false
            end repeat;
            END
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-03-04
              • 1970-01-01
              • 1970-01-01
              • 2013-03-13
              • 1970-01-01
              • 2015-07-12
              • 1970-01-01
              相关资源
              最近更新 更多