SQLServer获得随机数有两种方法:
一、使用rand获得随机数
二、使用Checksum结合NewID获得随机数
一、使用rand
(1)Rand()函数是系统自带的获取随机数的函数,可以直接运行select rand() 获取0~1之间的float型的数字,类似的,如果想获得例如1~100之间的整数随机数可以运行 select round(100*rand(),0)
eg:得到60~100的随机数,小数点后保留两位
DECLARE @NumBegin Int=60 --随机数的最小值
DECLARE @NumEnd Int=100 --随机数的最大值
DECLARE @Decimal Int=2 --保留小数点几位
SELECT @NumBegin+round((@NumEnd-@NumBegin)*rand(),@Decimal)
如果将2改为-1,则变成获取60~100之间的10的倍数的整数,原因在于:这里的round(表达式,长度,操作方式)函数会返回一个数值,舍入到指定的长度,这里的操作方式默认为0,操作方式为0遵循的是四舍五入,指定其他整数值则直接截断。
(返回的数值和原数值的总位数始终没有变化)
关于长度:舍入精度
a)如果长度为正数,则将数值舍入到长度指定的小数位数。
b)如果长度为负数,则将数值小数点左边部分舍入到长度指定的长度。注意如果长度为负数,并且大于小数点前的数字个数,则将返回 0。
c)如果长度为负数并且等于小数点前的数字个数且操作方式为四舍五入时,最前面的一位小于5返回0,大于等于5会导致错误出现,如果操作方法不是四舍五入时则不会出现错误,返回结果一律为0。
(2)rand()函数用在函数内部会报错“在函数内对带副作用的运算符‘rand’的使用无效”,但可以通过作为参数传参实现:
eg:
CREATE FUNCTION Scalar_CheckSumNEWIDQ
(
@From int,
@To int,
@Keep int,
@RAND float
)
RETURNS float
BEGIN
RETURN @From+round((@To-@From)*@RAND,@Keep)
END
GO
SELECT dbo.Scalar_CheckSumNEWIDQ(20,30,6,RAND())
这里即使参数相同,多次运行都可以得到范围内不同的随机数
二、使用Checksum结合NewID
(1) Checksum:总和检验码,校验和。在数据处理和数据通信领域中,用于校验目的的一组数据项的和。这些数据项可以是数字或在计算检验总和过程中看作数字的其它字符串。它通常是以十六进制为数制表示的形式,如果校验和的数值超过十六进制的FF,也就是255. 就要求其补码作为校验和.通常用来在通信中,尤其是远距离通信中保证数据的完整性和准确性
(2) 在SQLServer中Checksum()需要传入1个参数,可以是任何类型
eg:
SELECT CHECKSUM(1) --1
SELECT CHECKSUM('A') --114
SELECT CHECKSUM('AA') --34472462
SELECT CHECKSUM(GETDATE()) --18516390
可以看出传入不同参数就有不同的返回值,每个参数的返回值都是固定的,而且还有可能会出现负数的,并看不出有什么规律
(3)因此,我们可以通过传入newid()来获得随机数,因为newid()每次获得的值都是唯一的随机的。
eg:
SELECT CHECKSUM(NEWID()) UNION ALL
SELECT CHECKSUM(NEWID()) UNION ALL
SELECT CHECKSUM(NEWID()) UNION ALL
SELECT CHECKSUM(NEWID())
结果为:
注:这里的UNION ALL只是结果集的堆叠输出,要与之区别的还有union:
1.union会去除结果集中重复的部分,相当于进行一个distinct(去重),并且union 会自带排序功能;
2.union all 会不管是否重复,都会将结果合并在一起输出,没有排序功能,只是结果集的堆叠输出
(4)在函数中的使用,也只能通过传参的方法
eg:
CREATE FUNCTION aaa
(
@From int,
@To int,
@Keep int,
@newid varchar(50)
)
RETURNS float
BEGIN
DECLARE @ResultVar float
SELECT @ResultVar=CONVERT(BIGINT,RIGHT(ABS(CHECKSUM(@newid)),9))*0.1/100000000
RETURN @From+round((@To-@From)*@ResultVar,@Keep)
END
SELECT dbo.aaa(20,30,6,'NEWID()')
由于CHECKSUM()得到的数是固定的,所以同一组参数多次运行出现的结果是相同的
注:ABS() 绝对值函数
RIGHT(表达式,n) 取表达式从右数起n个字符
CONVERT() 数据类型转换
9与*0.1/100000000 对应,使得@ResultVar随机得到的数是0~1之间的数,类似于函数rand()的功能
三、两种方法的比较
(1)稍加处理,CHECKSUM也可以当作rand来使用
eg:从结果看出都可以得到随机数
SELECT CHECKSUM=CONVERT(BIGINT,RIGHT(ABS(CHECKSUM(NEWID())),9))*0.1/100000000 ,RAND=RAND() UNION ALL
SELECT CHECKSUM=CONVERT(BIGINT,RIGHT(ABS(CHECKSUM(NEWID())),9))*0.1/100000000 ,RAND=RAND() UNION ALL
SELECT CHECKSUM=CONVERT(BIGINT,RIGHT(ABS(CHECKSUM(NEWID())),9))*0.1/100000000 ,RAND=RAND() UNION ALL
SELECT CHECKSUM=CONVERT(BIGINT,RIGHT(ABS(CHECKSUM(NEWID())),9))*0.1/100000000 ,RAND=RAND()
结果为:
(2)但rand函数有个弊端,若我们想在一张表的每一元组后面生成一个唯一的随机数时(即在表中添加一列随机数),只能用CHECKSUM和NEWID来实现
原因在于:使用rand会出现相同的随机数,然而这并不是我们想要的
eg:
SELECT *,RAND() '随机数' FROM Product
结果为:
SELECT *,NEWID() '随机数' FROM Product
结果为:
类似的:
SELECT id ,CHECKSUM=CONVERT(BIGINT,RIGHT(ABS(CHECKSUM(NEWID())),9))*0.1/100000000 ,RAND=RAND() from Product
得到的结果是: