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

w8biq8rn  于 2021-06-18  发布在  Mysql
关注(0)|答案(3)|浏览(296)

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

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

这是错误:
1064年的今天,“where”附近的语法有问题 NUM 不在(选择 PHONE_NUMBERPHONE )'在第1行

oknwwptz

oknwwptz1#

@gordonlinoff answer的一个问题是,它可能不返回任何内容,而返回另一个表中不存在的数字。有两种方法可以解决这个问题:使用存储函数,或者使用数字表。以下是如何使用存储函数:

  1. DELIMITER //
  2. DROP FUNCTION IF EXISTS get_random_phone //
  3. CREATE FUNCTION get_random_phone(min INT, max INT) RETURNS INT
  4. NOT DETERMINISTIC
  5. BEGIN
  6. DECLARE num INT;
  7. DECLARE finished INT DEFAULT 0;
  8. DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
  9. REPEAT
  10. SET num = min + FLOOR(RAND() * (max - min + 1));
  11. SELECT phone_number INTO num FROM phone WHERE phone_number = num;
  12. UNTIL finished = 1
  13. END REPEAT;
  14. RETURN num;
  15. END //

然后您的查询就变成

  1. SELECT get_random_phone(10000, 99999)

或者,您可以创建一个数字表 LEFT JOIN 在电话号码表中,只选择不匹配的行,然后按排序 RAND() 以及使用 LIMIT 1 只返回一个结果。但是请注意,如果没有索引,这可能会非常慢 num 以及 phone_number .

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

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

  1. SELECT num
  2. FROM numbers
  3. LEFT JOIN phone ON phone.phone_number = numbers.num
  4. WHERE phone.phone_number IS NULL AND num BETWEEN 10000 AND 99999
  5. ORDER BY RAND()
  6. LIMIT 1
展开查看全部
nwlls2ji

nwlls2ji2#

你可以做:

  1. SELECT NUM
  2. FROM (SELECT round(RAND()*99999) AS `NUM`) x
  3. WHERE `NUM` NOT IN (SELECT `PHONE_NUMBER` FROM `PHONE`);
  4. ``` `NUM` 现在还不知道 `WHERE` 条款。而且,你不能有一个 `WHERE` 没有一个 `FROM` .
zrfyljdw

zrfyljdw3#

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

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

但是,虽然这确实选择了一个介于10000和99999之间的数字,但它只能在之后检查它是否不存在。如果检查失败,查询将不返回任何内容,您必须重试(或者使用联合使其复杂化,这仍然不能提供绝对的保证)。
另一种可能是生成另一个表,其中所有数字都在10000到99999之间,然后运行 LEFT JOIN 请求右侧为空。然后你必须从结果中随机选择一个条目;我不确定,但在这种情况下,您可能需要运行order by rand(),然后运行limit 1来提取一条记录,然后可能选择90万条记录。这将是昂贵的(但见最后的答案)。
如果phone表几乎是空的,最有效的方法是使用存储过程并继续运行第一个查询(或者在生成之后执行一个检查),直到它成功为止,如果phone表是稀疏的,它应该在很少的尝试内完成。
否则,您可以用所有号码预先填充电话表(该表已被大量填充,因此这不是一个很大的额外成本),并添加一列声明该号码是“免费”的。然后从表中选择一个随机条目,条件是自由标记产生true。在这种情况下,你会想读这个答案。

相关问题