用MySQL里的Rand()生成 不连续重复 的随机数年龄以及随机姓名字符串

前言:
          RAND函数, 返回在范围0到1.0内的随机浮点值。如果一个整数参数N被指定,它被用作种子值。

一,朋友问题描述如下:
(1),有一个用户表,有id,用户的真实名字,年龄。
通过一段存储过程来实现向表里插入100数据,其中年龄随机
姓名 
姓氏:’赵钱孙李周吴郑王’;,随机取出一个
名字:’一段文字字符串’,随机的取出一个字或者两个字
要求:随机的名字不能出现连续重复。

(2),然后我写出的代码如下:
-- 创建用户表,在project里
create table user1 (
id int not null primary key auto_increment,
name varchar(3) not null,
age tinyint not null
) charset utf8;

-- 创建存储过程
delimiter $$
create procedure pro3(num int)
begin
declare fname char(1);
declare name1 char(1);
declare name2 char(1);
declare fullname varchar(3);
declare age int;
declare i int default 1;

while i <=num do
set fname = substring('赵钱孙李周吴郑王',floor(1+8*rand()),1);  -- 姓
set name1 = substring('一二三四五六七八九十甲乙丙丁',floor(1+14*rand()),1); -- 抽一个字
set name2 = substring('一二三四五六七八九十甲乙丙丁',floor(1+14*rand()),1); -- 抽一个字

if round(rand())=0 then  -- 创造一个局部变量fullname代表全名,随机确定是两个字还是三个字
set fullname = concat(fname,name1);
end if;
if round(rand())=1 then
set fullname = concat(fname,name1,name2);
end if;
set age = floor(20+31*rand());  -- 年龄为20-50的随机
insert into user1 values(null,fullname,age);  -- 插入数据
set i = i + 1; 
end while;
end
$$
delimiter ;

(3),执行结果
call pro3(100); -- 执行过程
出现的结果出乎意料,出现了很多连续一样的姓名,执行结果如下:
mysql> select * from user1;
+-----+--------+-----+
| id  | name   | age |
+-----+--------+-----+
|   1 | 赵三       |  28 |
|   2 | 孙一四      |  50 |
|   3 | 郑丁九      |  42 |
|   4 | 王八       |  47 |
|   5 | 钱六      |  48 |
|   6 | 李五       |  26 |
|   7 | 李五       |  41 |
|   8 | 郑二三      |  22 |
|   9 | 孙七六       |  24 |
|  10 | 孙三       |  21 |
|  11 | 钱甲二     |  26 |
|  12 | 孙丙       |  42 |
|  13 | 孙丙       |  37 |
|  14 | 赵六丁       |  24 |
|  15 | 赵六丁       |  40 |
|  16 | 王十七      |  28 |
|  17 | 孙九       |  22 |
|  18 | 李二       |  23 |
|  19 | 李十      |  23 |
|  20 | 赵丁甲      |  50 |
|  21 | 钱一九     |  49 |
|  22 | 钱一九     |  22 |
|  23 | 钱一九     |  30 |
|  24 | 钱一九     |  30 |
|  25 | 孙五       |  46 |
|  26 | 吴三十      |  39 |
|  27 | 赵七二      |  50 |
|  28 | 赵七二      |  29 |
|  29 | 孙甲九      |  20 |
|  30 | 郑乙十     |  35 |
|  31 | 周一      |  50 |
|  32 | 吴甲七       |  50 |
|  33 | 李丁十     |  47 |
|  34 | 李丁十     |  29 |
|  35 | 李丁十     |  40 |
|  36 | 孙五       |  47 |
|  37 | 赵九丙     |  41 |
|  38 | 郑三八      |  43 |
|  39 | 钱七      |  37 |
|  40 | 钱二一     |  24 |
|  41 | 王七五       |  45 |
|  42 | 李十四      |  24 |
|  43 | 李十四      |  28 |
|  44 | 孙甲甲      |  49 |
|  45 | 郑五      |  38 |
|  46 | 赵甲      |  27 |
|  47 | 王三       |  39 |
|  48 | 王三       |  26 |
|  49 | 王三       |  22 |
|  50 | 王三       |  30 |
|  51 | 钱一九     |  44 |
|  52 | 赵四       |  30 |
|  53 | 王十九      |  50 |
|  54 | 王十九      |  34 |
|  55 | 王十九      |  40 |
|  56 | 周丙甲      |  20 |
|  57 | 孙十      |  47 |
|  58 | 王丙       |  32 |
|  59 | 王六       |  43 |
|  60 | 吴三甲       |  29 |
|  61 | 王乙       |  26 |
|  62 | 赵甲      |  46 |
|  63 | 赵甲      |  23 |
|  64 | 王八丙      |  25 |
|  65 | 王八丙      |  30 |
|  66 | 周乙六       |  50 |
|  67 | 吴五八       |  21 |
|  68 | 孙五       |  42 |
|  69 | 赵丙六      |  48 |
|  70 | 周三       |  48 |
|  71 | 周三       |  47 |
|  72 | 李乙       |  46 |
|  73 | 李乙       |  40 |
|  74 | 吴十五      |  45 |
|  75 | 赵十五      |  36 |
|  76 | 赵十五      |  25 |
|  77 | 李十      |  35 |
|  78 | 李甲       |  38 |
|  79 | 周三一      |  33 |
|  80 | 周三一      |  48 |
|  81 | 钱六六      |  33 |
|  82 | 钱六六      |  49 |
|  83 | 孙十六      |  36 |
|  84 | 王二甲       |  48 |
|  85 | 王二甲       |  39 |
|  86 | 王乙       |  30 |
|  87 | 郑三      |  21 |
|  88 | 赵二五      |  29 |
|  89 | 周丙丙      |  43 |
|  90 | 钱七乙      |  35 |
|  91 | 钱七乙      |  47 |
|  92 | 钱七乙      |  38 |
|  93 | 孙乙       |  29 |
|  94 | 周乙       |  32 |
|  95 | 郑乙十     |  46 |
|  96 | 郑乙十     |  37 |
|  97 | 吴八       |  46 |
|  98 | 吴十八      |  42 |
|  99 | 王乙四       |  30 |
| 100 | 吴九十      |  50 |

二,分析原因
因为才14个汉字中取一个(数据源太少了),而且连续执行100次,有连续出现重复的随机数是正常的,应该是底层的rand算法没有考虑过滤到连续重复的情况,我们不好去改动底层的mysql源码,但是可以在存储过程中做一个判断,来过滤掉连续重复的情况,思路是如果重复,就重新取一个不重复的。

所以存储过程改动如下:

  1. DELIMITER $$
  2. USE `test`$$
  3. DROP PROCEDURE IF EXISTS `pro3`$$
  4. CREATE PROCEDURE `pro3`(num INT)
  5. BEGIN
  6. DECLARE fname CHAR(1);
  7. DECLARE name1 CHAR(1);
  8. DECLARE name2 CHAR(1);
  9. DECLARE fullname VARCHAR(3);
  10. DECLARE pre_fullname VARCHAR(3) DEFAULT \'\';
  11. DECLARE age INT;
  12. DECLARE i INT DEFAULT 1;
  13. WHILE i <=num DO
  14.     SET fname = SUBSTRING(\'赵钱孙李周吴郑王\',FLOOR(1+8*RAND()),1); 
  15.     SET name1 = SUBSTRING(\'一二三四五六七八九十甲乙丙丁\',ROUND(1+14*RAND()),1); 
  16.     SET name2 = SUBSTRING(\'一二三四五六七八九十甲乙丙丁\',ROUND(1+14*RAND()),1); 

  17.     IF ROUND(RAND())=0 THEN 
  18.     SET fullname = CONCAT(fname,name1);
  19.     END IF;
  20.     IF ROUND(RAND())=1 THEN
  21.     SET fullname = CONCAT(fname,name1,name2);
  22.     END IF;

  23.     SET age = FLOOR(20+31*RAND()); 
  24.     /* 给临时变量赋值,看最新的一条记录的name值 */
  25.     SELECT NAME INTO pre_fullname FROM user1 ORDER BY id DESC LIMIT 1;
  26.     /* 开始判断,如果刚赋值的name跟上一次赋值的name值一样,就跳过,i保持不变,继续取值;否则i+1,继续循环取值*/
  27.     IF fullname=pre_fullname AND i>1 THEN
  28.         SET i=i;
  29.     ELSEIF fullname IS NULL THEN
  30.         SET i=i;        
  31.     ELSE
  32.         INSERT INTO user1 VALUES(NULL,fullname,age); 
  33.         SET i = i + 1; 
  34.     END IF ;
  35. END WHILE;
  36. END$$
  37. DELIMITER

三,执行改动后的存储过程,查看效果
执行结果如下:
  1. mysql> DELIMITER $$
  2. mysql> USE `test`$$
  3. Database changed
  4. mysql> DROP PROCEDURE IF EXISTS `pro3`$$
  5. Query OK, 0 rows affected, 1 warning (0.00 sec)

  6. mysql> CREATE PROCEDURE `pro3`(num INT)
  7.     -> BEGIN
  8.     -> DECLARE fname CHAR(1);
  9.     -> DECLARE name1 CHAR(1);
  10.     -> DECLARE name2 CHAR(1);
  11.     -> DECLARE fullname VARCHAR(3);
  12.     -> DECLARE pre_fullname VARCHAR(3) DEFAULT \'\';
  13.     -> DECLARE age INT;
  14.     -> DECLARE i INT DEFAULT 1;
  15.     -> WHILE i <=num DO
  16.     -> SET fname = SUBSTRING(\'赵钱孙李周吴郑王\',FLOOR(1+8*RAND()),1); 
  17.     -> SET name1 = SUBSTRING(\'一二三四五六七八九十甲乙丙丁\',ROUND(1+14*RAND()),1); 
  18.     -> SET name2 = SUBSTRING(\'一二三四五六七八九十甲乙丙丁\',ROUND(1+14*RAND()),1); 
  19.     -> 
  20.     -> IF ROUND(RAND())=0 THEN 
  21.     -> SET fullname = CONCAT(fname,name1);
  22.     -> END IF;
  23.     -> IF ROUND(RAND())=1 THEN
  24.     -> SET fullname = CONCAT(fname,name1,name2);
  25.     -> END IF;
  26.     -> 
  27.     -> SET age = FLOOR(20+31*RAND()); 
  28.     -> /* 给临时变量赋值,看最新的一条记录的name值 */
  29.     -> SELECT NAME INTO pre_fullname FROM user1 ORDER BY id DESC LIMIT 1;
  30.     -> /* 开始判断,如果刚赋值的name跟上一次赋值的name值一样,就跳过,i保持不变,继续取值;否则i+1,继续循环取值*/
  31.     -> IF fullname=pre_fullname AND i>1 THEN
  32.     -> 
  33. Display all 799 possibilities? (or n) 
  34.     -> SET i=i;
  35.     -> ELSEIF fullname IS NULL THEN
  36.     -> 
  37. Display all 799 possibilities? (or n) 
  38.     -> SET i=i;
  39. Display all 799 possibilities? (or n) 
  40.     -> SET i=i;
  41.     -> ELSE
  42.     -> 
  43. Display all 799 possibilities? (or n) 
  44.     -> INSERT INTO user1 VALUES(NULL,fullname,age); 
  45.     -> 
  46. Display all 799 possibilities? (or n) 
  47.     -> SET i = i + 1; 
  48.     -> END IF ;
  49.     -> END WHILE;
  50.     -> END$$
  51. Query OK, 0 rows affected (0.00 sec)

  52. mysql> DELIMITER ;
  53. mysql> 
  54. mysql> truncate table user1;
  55. Query OK, 0 rows affected (0.01 sec)

  56. mysql> select * from user1;
  57. Empty set (0.00 sec)

  58. mysql> call pro3(100);
  59. Query OK, 1 row affected (0.11 sec)

  60. mysql> select * from user1;
  61. +-----+-----------+-----+
  62. | id | name | age |
  63. +-----+-----------+-----+
  64. | 1 | 吴甲九 | 32 |
  65. | 2 | 赵丙 | 49 |
  66. | 3 | 钱二 | 40 |
  67. | 4 | 郑二丙 | 34 |
  68. | 5 | 孙四三 | 39 |
  69. | 6 | 钱五十 | 39 |
  70. | 7 | 赵五 | 23 |
  71. | 8 | 郑九 | 22 |
  72. | 9 | 钱九七 | 47 |
  73. | 10 | 郑七乙 | 39 |
  74. | 11 | 孙丙二 | 44 |
  75. | 12 | 吴三九 | 30 |
  76. | 13 | 钱九四 | 28 |
  77. | 14 | 王十九 | 49 |
  78. | 15 | 周丙乙 | 43 |
  79. | 16 | 王十 | 33 |
  80. | 17 | 钱乙七 | 36 |
  81. | 18 | 赵七四 | 32 |
  82. | 19 | 郑八二 | 31 |
  83. | 20 | 赵二 | 35 |
  84. | 21 | 赵丙 | 26 |
  85. | 22 | 郑甲丁 | 38 |
  86. | 23 | 周丙九 | 50 |
  87. | 24 | 李丙五 | 27 |
  88. | 25 | 李五三 | 37 |
  89. | 26 | 孙丙六 | 46 |
  90. | 27 | 钱八 | 37 |
  91. | 28 | 周七六 | 40 |
  92. | 29 | 李一一 | 45 |
  93. | 30 | 钱十七 | 22 |
  94. | 31 | 吴七一 | 49 |
  95. | 32 | 吴丙六 | 39 |
  96. | 33 | 吴四四 | 50 |
  97. | 34 | 郑八丙 | 28 |
  98. | 35 | 吴五七 | 26 |
  99. | 36 | 吴甲 | 46 |
  100. | 37 | 钱四 | 39 |
  101. | 38 | 王丙九 | 24 |
  102. | 39 | 王八八 | 38 |
  103. | 40 | 吴乙丙 | 35 |
  104. | 41 | 吴丙七 | 39 |
  105. | 42 | 周甲丁 | 31 |
  106. | 43 | 钱二甲 | 25 |
  107. | 44 | 钱五丁 | 32 |
  108. | 45 | 孙四二 | 28 |
  109. | 46 | 李七丙 | 37 |
  110. | 47 | 钱七七 | 46 |
  111. | 48 | 郑乙四 | 33 |
  112. | 49 | 钱甲丁 | 34 |
  113. | 50 | 王五 | 37 |
  114. | 51 | 吴一 | 44 |
  115. | 52 | 王二十 | 33 |
  116. | 53 | 郑四 | 41 |
  117. | 54 | 钱九八 | 29 |
  118. | 55 | 李十十 | 24 |
  119. | 56 | 钱六七 | 44 |
  120. | 57 | 王二 | 38 |
  121. | 58 | 周五 | 36 |
  122. | 59 | 吴九 | 44 |
  123. | 60 | 赵丙 | 38 |
  124. | 61 | 李五五 | 20 |
  125. | 62 | 王八乙 | 33 |
  126. | 63 | 王丙八 | 49 |
  127. | 64 | 王九六 | 38 |
  128. | 65 | 钱七 | 45 |
  129. | 66 | 赵二二 | 36 |
  130. | 67 | 钱五乙 | 40 |
  131. | 68 | 孙甲七 | 43 |
  132. | 69 | 郑甲五 | 47 |
  133. | 70 | 赵丙 | 20 |
  134. | 71 | 郑四 | 43 |
  135. | 72 | 孙丙五 | 24 |
  136. | 73 | 孙三 | 33 |
  137. | 74 | 赵四乙 | 31 |
  138. | 75 | 李 | 44 |
  139. | 76 | 吴九丁 | 43 |
  140. | 77 | 郑甲一 | 33 |
  141. | 78 | 李三五 | 37 |
  142. | 79 | 王二 | 31 |
  143. | 80 | 赵七丙 | 35 |
  144. | 81 | 吴三十 | 22 |
  145. | 82 | 李二 | 50 |
  146. | 83 | 李八 | 49 |
  147. | 84 | 王一 | 27 |
  148. | 85 | 王三 | 22 |
  149. | 86 | 周五 | 45 |
  150. | 87 | 郑八 | 44 |
  151. | 88 | 郑甲二 | 48 |
  152. | 89 | 赵乙 | 37 |
  153. | 90 | 周四五 | 30 |
  154. | 91 | 周二七 | 41 |
  155. | 92 | 孙四 | 21 |
  156. | 93 | 周丙七 | 24 |
  157. | 94 | 孙丁乙 | 32 |
  158. | 95 | 周九一 | 20 |
  159. | 96 | 周九 | 32 |
  160. | 97 | 赵二一 | 26 |
  161. | 98 | 周丁五 | 47 |
  162. | 99 | 孙三 | 38 |
  163. | 100 | 吴十四 | 29 |
  164. +-----+-----------+-----+
  165. 100 rows in set (0.00 sec)

  166. mysql>
从中看到已经连续100个随机数中,没有出现连续重复的姓名和年龄。


四,RAND()与RAND(N)区别
每个种子产生的随机数序列是不同的,如果传入N参数执行RAND(N),则每次查询到的随机数都是固定的,如果没有传入N参数,则每次都是随机的值。如下所示:

  1. mysql> SELECT RAND(),RAND(5);
  2. +--------------------+---------------------+
  3. | RAND() | RAND(5) |
  4. +--------------------+---------------------+
  5. | 0.7946587333405938 | 0.40613597483014313 |
  6. +--------------------+---------------------+
  7. 1 row in set (0.00 sec)


  8. mysql> SELECT RAND(),RAND(5);
  9. +---------------------+---------------------+
  10. | RAND() | RAND(5) |
  11. +---------------------+---------------------+
  12. | 0.12910866749389904 | 0.40613597483014313 |
  13. +---------------------+---------------------+
  14. 1 row in set (0.00 sec)


  15. mysql> SELECT RAND(),RAND(5);
  16. +-------------------+---------------------+
  17. | RAND() | RAND(5) |
  18. +-------------------+---------------------+
  19. | 0.261567168181359 | 0.40613597483014313 |
  20. +-------------------+---------------------+
  21. 1 row in set (0.00 sec)


  22. mysql> SELECT RAND(),RAND(5);
  23. +--------------------+---------------------+
  24. | RAND() | RAND(5) |
  25. +--------------------+---------------------+
  26. | 0.9205098691587428 | 0.40613597483014313 |
  27. +--------------------+---------------------+
  28. 1 row in set (0.00 sec)


  29. mysql> SELECT RAND(),RAND(5);
  30. +--------------------+---------------------+
  31. | RAND() | RAND(5) |
  32. +--------------------+---------------------+
  33. | 0.8178478719832821 | 0.40613597483014313 |
  34. +--------------------+---------------------+
  35. 1 row in set (0.00 sec)


  36. mysql>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值