如何插入 MySQL table 中不存在的随机数?

How to insert a random number which is not present in MySQL table?

主查询

$sql = "INSERT INTO foldertable ( folderid )
             SELECT (
                        SELECT random_num
                        FROM (
                                SELECT FLOOR(RAND() * 4 + 1) AS random_num
                        ) AS numbers_mst_plus_1
                        WHERE random_num NOT IN (
                            0,1
                        )
                                  )";

问题

它插入一个随机数。但有时它只是插入 0 .

我算什么?

当下面SQL returns一个等于0或1的数时,就是插入零。

SELECT random_num
                        FROM (
                                SELECT FLOOR(RAND() * 4 + 1) AS random_num
                        ) AS numbers_mst_plus_1
                        WHERE random_num NOT IN (
                            0,1
                        )

我想要什么?

select 查询到 select 一个数字,直到它对于该列是唯一的。

尝试:-

我创建了一个 select 语句,其中 selects 1,2,3,4,5

SELECT random_num
        FROM (
           SELECT 1 AS random_num
           UNION 
           SELECT 2 AS random_num
           UNION 
           SELECT 3 AS random_num
           UNION 
           SELECT 4 AS random_num
           UNION 
           SELECT 5 AS random_num
       ) AS numbers_mst_plus_1

然后尝试在 INSERT QUERY

中实现它
$sql = "INSERT INTO foldertable ( folderid )
            SELECT (SELECT random_num FROM (SELECT 1 AS random_num UNION SELECT 2 AS random_num) AS temp_table WHERE random_num NOT IN (1) LIMIT 1
                    )

上面的查询总是将 2 插入 table,我很高兴。 然后我想如果 NOT IN 中同时存在 1 和 2(真实的,例如 Not in 子句包含 Table 中存在的所有文件夹 ID)

问题就在那里 -----

$sql = "INSERT INTO foldertable ( folderid )
            SELECT (SELECT random_num FROM (SELECT 1 AS random_num UNION SELECT 2 AS random_num) AS temp_table WHERE random_num NOT IN (1 , 2) LIMIT 1
                    )
            ";

现在又在folderid 列中输入0

所以我添加了一个 WHERE 条款

$sql = "INSERT INTO foldertable ( folderid )
            SELECT (SELECT random_num FROM
                                        (SELECT 1 AS random_num UNION SELECT 2 AS random_num UNION SELECT 3 AS random_num )
                                        AS temp_table
                                        WHERE random_num
                                        NOT IN (
                                                SELECT folderid FROM foldertable
                                                )
                                        LIMIT 1
                    )
            WHERE ((SELECT COUNT(*) FROM foldertable) < 3)
            ";

所以现在如果所有 ID 都被使用,它不会添加新行。

但真正让人头疼的是写作

           SELECT 1 AS random_num
           UNION 
           SELECT 2 AS random_num
           UNION 
           SELECT 3 AS random_num
           UNION 
           SELECT 4 AS random_num
           UNION 
           SELECT 5 AS random_num
           .... 100000000 times 
           UNION
           SELECCT 100000006 AS random_num

所以那不值得花时间

上帝来了FOR LOOP

$randomNoString = "";
    for ($i=0; $i < ($maxFolderId - $minFolderId + 1 ); $i++) { 
        if($i === 0){
            $randomNoString ="SELECT ".($minFolderId + $i) . " AS random_num" ;
        }
        else {
            $randomNoString =  $randomNoString ." UNION " . "SELECT ".($minFolderId + $i) . " AS random_num";
        }
    }

$sql = "INSERT INTO foldertable ( folderid )
        SELECT (SELECT random_num FROM
                                    ({$randomNoString})
                                    AS temp_table
                                    WHERE random_num
                                    NOT IN (
                                            SELECT folderid FROM foldertable
                                            )
                                    LIMIT 1
                )
        WHERE ((SELECT COUNT(*) FROM foldertable) < {$maxFolderCount})
        ";

有什么问题

1。现在文件夹 ID 是唯一的但不是随机的。 2. 我的脑袋说这会造成性能问题。

我不能做什么

  1. 无法将 folderid 设置为唯一。

另一个想法如果我想要一个 6 个字符的字符串。 ,我该怎么做?

计划 A -- 哈希:

使用散列函数创建一个新号码。这取决于 table 已经有一个 AUTO_INCREMENT id:

SELECT MD5(MAX(id)) FROM t

优点:简单、快速

缺点:需要 id,“数字”实际上是一个 32 个字符的十六进制字符串。

B 计划 -- 预建列表:

  1. 构建了一个 table nums 数字 100..50000.

  2. 将它们洗牌成不同的 table:

     CREATE TABLE rand_nums
         SELECT num FROM nums ORDER BY RAND();
    
  3. 提取一个数字

     SELECT num FROM rand_nums LIMIT 1;      -- get
     DELETE FROM rand_nums WHERE num = ...;  -- remove
    

优点:高效(设置后_

缺点:需要更多的复杂性来处理第 3 步中同时获取数字和提高效率

C 计划 -- 其他想法

如果您后退一个步骤,您可能会发现更高级别的目标可能会被其他一些技术所取代。您可能需要“获取随机行”作为原始数据。如果是这样,这里有一些“相当不错”的技巧:http://mysql.rjweb.org/doc.php/random

关于:

另一个想法如果我想要一个 6 个字符的字符串。 , 我该怎么做呢?

select concat(
    cast(char(64+floor(rand()*26+1)) as char),
    cast(char(64+floor(rand()*26+1)) as char),
    cast(char(64+floor(rand()*26+1)) as char),
    cast(char(64+floor(rand()*26+1)) as char),
    cast(char(64+floor(rand()*26+1)) as char),
    cast(char(64+floor(rand()*26+1)) as char)) as char6;

或者,如果您想要更长的语句:

with recursive cte as ( 
   select 'A' as a
   union all 
   select CHAR(ORD(a)+1)
   from cte
   where a<'Z') 
select concat(c1.a,c2.a,c3.a,c4.a,c5.a,c6.a) as char6
from cte c1
cross join (select a from cte order by rand()*26+1 limit 1) c2
cross join (select a from cte order by rand()*26+1 limit 1) c3
cross join (select a from cte order by rand()*26+1 limit 1) c4
cross join (select a from cte order by rand()*26+1 limit 1) c5
cross join (select a from cte order by rand()*26+1 limit 1) c6
order by rand()*26+1
limit 1;