生成另一个表MySQL中不存在的随机值

时间:2018-11-04 20:43:54

标签: mysql sql

我的SQL语法有问题。我想添加一个介于10000和99999之间的随机电话号码。到目前为止,我有这个查询,但是我无法在PHPMyAdmin中运行它:

SELECT round(RAND()*99999) AS `NUM` 
WHERE `NUM` NOT IN (SELECT `PHONE_NUMBER` FROM `PHONE`);

这是错误:

  

1064-第1行上“ WHERE NUM NOT IN(从PHONE_NUMBER中选择PHONE的地方(选择{{1}})附近的语法错误”

3 个答案:

答案 0 :(得分:3)

您可以这样做:

SELECT NUM
FROM (SELECT round(RAND()*99999) AS `NUM`) x 
WHERE `NUM` NOT IN (SELECT `PHONE_NUMBER` FROM `PHONE`);

NUMWHERE子句中未知。而且,如果没有WHERE,就不会拥有FROM

答案 1 :(得分:0)

@GordonLinoff答案的一个问题是,它可能不返回任何值,而是返回另一个表中不存在的数字。有两种解决方法:使用存储的函数或使用数字表。这是通过存储的函数来完成的:

DELIMITER //
DROP FUNCTION IF EXISTS get_random_phone //
CREATE FUNCTION get_random_phone(min INT, max INT) RETURNS INT
NOT DETERMINISTIC
BEGIN
  DECLARE num INT;
  DECLARE finished INT DEFAULT 0;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
  REPEAT
    SET num = min + FLOOR(RAND() * (max - min + 1));
    SELECT phone_number INTO num FROM phone WHERE phone_number = num;
  UNTIL finished = 1
  END REPEAT;
  RETURN num;
END //

然后您的查询就变成

SELECT get_random_phone(10000, 99999)

或者,您可以创建一个数字表,然后LEFT JOIN到电话号码表,仅选择不匹配的行,然后按RAND()进行排序,并使用LIMIT 1仅返回一个结果。请注意,尽管在numphone_number上没有索引会很慢。

CREATE TABLE numbers (num INT PRIMARY KEY) AS
SELECT n1.n + n10.n*10 + n100.n*100 + n1000.n*1000 + n10000.n*10000 AS num FROM
(SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) n1
CROSS JOIN
(SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) n10
CROSS JOIN
(SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) n100
CROSS JOIN
(SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) n1000
CROSS JOIN
(SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) n10000
ORDER BY NUM

在这种情况下,您的查询将是:

SELECT num
FROM numbers
LEFT JOIN phone ON phone.phone_number = numbers.num
WHERE phone.phone_number IS NULL AND num BETWEEN 10000 AND 99999
ORDER BY RAND()
LIMIT 1

答案 2 :(得分:0)

不上班。最接近的方法是这样,通过包装到子查询中来保护您的第一个查询:

SELECT NUM
    FROM (SELECT 10000 + ROUND(RAND()*89999) AS NUM) AS SUBQ
    WHERE NUM NOT IN (SELECT PHONE_NUMBER FROM PHONE);

但是,尽管它确实选择了10000到99999之间的一个数字,但它只能在之后检查其不存在。如果检查失败,查询将不返回任何内容,而您将不得不重试(或使用UNION使其复杂化,但仍不能绝对保证)。

另一种可能性是生成另一个 all 编号在10000和99999之间的表,并运行LEFT JOIN,要求右侧为NULL。然后,您必须从该结果中选择一个随机条目;我不确定,但是在这种情况下,可能选择了九十万个之后,您可能必须先运行ORDER BY RAND(),然后执行LIMIT 1来提取一条记录。这将是昂贵的(但请参阅最后的答案)。

如果电话表几乎为空,最有效的方法是使用存储过程,并保持运行第一个查询(或先生成查询再生成查询),直到成功为止。电话表稀疏,应该在很少的尝试中进行。

否则,您可以用所有数字预填充电话表(该表已经被大量填充,因此这不是很大的额外费用),并添加一列指出该数字是“免费”的列。然后,您从表中选择一个随机条目,条件是自由标记产生true。在这种情况下,您需要阅读this answer