朋友们,我们经常会碰到这样的需求,比如我们需要在产品合格证上打印防伪二维码,二维码是一个微信小程序的链接网址,不同二维码通过链接网址中的一段随机字符串(或称为随机码、防伪码等)区分。因为有防伪需求,我们生成的随机字符串不能有固定规律、更不能重复。
随机数、随机码的需求场景
这类需求比较常见的有两种方式,一种方式以二维码为主,数字为辅,二维码用在消费者防伪查询使用,数字则主要内部使用或在二维码被破坏时备用。如下图所示:
还有一种方式,则是以物流条码配合二维码,物流条码用在企业生产和物流流转时通过PDA扫码调用,二维码则用作消费者通过微信小程序扫码进行防伪查询。如下图所示:
针对二维码中随时字符串部分,大多朋友的处理方式,是在客户端编程语言(比如Java、PHP、JS、Python等)中,通过代码生成随机数再存入数据库。如果只是生成少量数据,这种方式倒也可行,但合格证一般都是批量印刷的,产生的数据动辄上百万条,这在客户生成就显得太慢太慢了。
想要速度快,就不能在程序前端生成了随机码了,我后面会为大家提供在数据库中直接批量生成的解决方案,经过大量数据试验,速度还是很快的。
如何在数据库中获取随机数?
常用数据库系统中,都会有一个基本的随机数函数,在MySQL和SQL Server中,这个函数的名为rand;在PostgreSQL和SQLite中,名为random。
MySQL、SQL Server和pgSQL返回的是0~1的小数,SQLite返回的则是整数。MySQL和SQL Server的随机函数支持种子,pgSQL和SQLite则不支持。
下图是在SQL Server中生成随机数的例子:
可以看到,相同的种子,返回的随机数是固定的。
下图是MySQL中生成随机数的例子,可以发现相同的种子也是同样返回相同的随机数。
数据库返回的随机数一般都是伪随机数,除非种子不同,每次返回还是有较大概率会重复的。想要不重复就要设置不重复的种子。pgSQL不支持种子,想要不重复可以这样写:
selectfrandfromgenerate_series(1,1000000)ast(frand)orderbyrandom()limit100;
执行结果参看下图:
随机数虽然可以保证不重复,但只能是数字,而且种子支持整数的范围是有限的,比如SQL Server的种子只能支持从 -2^31 (-2,147,483,648) 到 2^31 - 1 (2,147,483,647) 的整型数据,这就决定了生成的随机数的位数也不会太长,搞个随机抽奖算法还是可以的,但要用来做“防伪”,显然是不够格的!
想要好的效果,我们还是要另想其它办法。
如果觉得《巧用SQL函数组合 生成各类随机数 随机码》对你有帮助,请点赞、收藏,并留下你的观点哦!