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

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

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

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

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

oknwwptz

oknwwptz1#

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

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 只返回一个结果。但是请注意,如果没有索引,这可能会非常慢 num 以及 phone_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
nwlls2ji

nwlls2ji2#

你可以做:

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

zrfyljdw3#

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

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

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

相关问题