如何插入 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. 我的脑袋说这会造成性能问题。
我不能做什么
- 无法将
folderid
设置为唯一。
另一个想法如果我想要一个 6 个字符的字符串。 ,我该怎么做?
计划 A -- 哈希:
使用散列函数创建一个新号码。这取决于 table 已经有一个 AUTO_INCREMENT id
:
SELECT MD5(MAX(id)) FROM t
优点:简单、快速
缺点:需要 id
,“数字”实际上是一个 32 个字符的十六进制字符串。
B 计划 -- 预建列表:
构建了一个 table nums
数字 100..50000.
将它们洗牌成不同的 table:
CREATE TABLE rand_nums
SELECT num FROM nums ORDER BY RAND();
提取一个数字
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;
主查询
$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. 我的脑袋说这会造成性能问题。
我不能做什么
- 无法将
folderid
设置为唯一。
另一个想法如果我想要一个 6 个字符的字符串。 ,我该怎么做?
计划 A -- 哈希:
使用散列函数创建一个新号码。这取决于 table 已经有一个 AUTO_INCREMENT id
:
SELECT MD5(MAX(id)) FROM t
优点:简单、快速
缺点:需要 id
,“数字”实际上是一个 32 个字符的十六进制字符串。
B 计划 -- 预建列表:
构建了一个 table
nums
数字 100..50000.将它们洗牌成不同的 table:
CREATE TABLE rand_nums SELECT num FROM nums ORDER BY RAND();
提取一个数字
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;