SQL Server中的RAND函数的介绍和区间随机数值函数的实现

所属分类: 数据库 / MsSql 阅读数: 1089
收藏 0 赞 0 分享

工作中会遇到SQL Server模拟数据生成以及数值列值(如整型、日期和时间数据类型)随机填充等等任务,这些任务中都要使用到随机数。鉴于此,本文将对SQL Server中随机数的使用简单做个总结 。

T-SQL 随机有关的三个函数

   RAND([seed] 此函数生成从0到1之间随机 float 值(详细说明查看https://technet.microsoft.com/zh-cn/library/ms177610(v=sql.90).aspx)。

    CHECKSUM ( * | expression [ ,...n ] ) 此函数生成按照表的某一行或一组表达式计算出来的int校验和值,CHECKSUM 用于生成哈希索引(详细说明查看https://technet.microsoft.com/zh-cn/library/ms189788(v=sql.90).aspx)。

    NEWID ( ) 此函数生成 uniqueidentifier 类型的唯一值(详细说明查看https://technet.microsoft.com/zh-cn/library/ms190348(v=sql.90).aspx)。

生成任意一个随机数值(如整数、日期和时间数据类型)

    如果获得任意一个随机整数值?函数RAND生成的结果是float数据类型的,显然很难满足要求,不过可以通过对函数RAND的结果继续加工(比如其结果乘以某一个值保留整数部分等等)得到要求。很显然,函数CHECKSUM生成的结果是int数据类型,很容易满足我们的结果,不过其参数如果固定(表的某一行值相同或一组表达式值相同),那么其结果也是相同的。函数NEWID可以保证结果的唯一,但是其结果是unigueidentifer数据类型的。

    从以上三个函数的结果值分析:函数RNAD和CHECKSUM的结果是能获得整数数值的。如果我们将函数NEWID的结果值作为函数CHECKSUM的参数,那么其每次生成的结果值都是不一样的int数据类型的数值。以下T-SQL代码如下:

SELECT CHECKSUM(NEWID()) AS CheckSumValue, CHECKSUM(NEWID()) AS CheckSumValue2;
GO

执行后的查询结果如下:

 

从上面的查询结果看到组合生成的整数数值都是9位数的,平时工作中大多使用的随机整数值都是不太大的且都是自然数(0和正整数的集合),这就要求限制随机生成的整数数值。可以使用函数ABS对其结果进行处理得到任意一个自然数。这样,组合一起来的格式就是这样的:ABS(CHECKSUM(NEWID()))。为了便于使用便于使用我们通过将其封装到函数中,但是函数NEWID又不能在函数中使用,那我们就要考虑其他的方式:将函数NEWID封装在单列单行的视图中。其定义视图的T-SQL代码如下:

 IF OBJECT_ID(N'dbo.vRandomGuid', 'V') IS NOT NULL
 BEGIN
   DROP VIEW dbo.vRandomGuid;
 END
 GO
 --==================================
 -- 功能: 随机Guid视图
 -- 说明: 具体实现阐述 
 -- 作者: XXX
 -- 创建: yyyy-MM-dd
 -- 修改: yyyy-MM-dd XXX 修改内容描述
 --==================================
 CREATE VIEW dbo.vRandomGuid
   --$Encode$--
 AS
   SELECT RandomGuid = NEWID();
 GO
 调用该视图的T-SQL代码如下:
 SELECT TOP RandomGuid
 FROM dbo.vRandomGuid;
 GO 

执行后的查询结果如下:

生成整数区间内的任意一个随机整数

上面的视图定义,我们继续讲解组合函数的进一步封装。我们先讲解如何限制随机生成的数值,取模运算可以实现生成在指定数值区间内的任意一个数值,例如:获取区间[3,5]内任意一个数字,我们设为区间的最小值为@intMin:3,最大值为@intMax,则该区间的间隔值为 @intMax - @intMin + 1: 5 - 3 + 1(3),那么针对任意的整数值设为为@intValue,然后对这个间隔值先进行取模运算在加上区间最小值,最后得到的值为: @intValue % (@intMax - @intMin + 1) + @intMin。如果@intValue为8,则结果值为5;如果@intValue为9,则结果值为3;如果@intValue为10,则结果值为4……

    针对以上的分析我们封装的T-SQL代码如下:

 IF OBJECT_ID(N'dbo.ufn_RandNum', 'FN') IS NOT NULL
 BEGIN
   DROP FUNCTION dbo.ufn_RandNum;
 END
 GO
 --==================================
 -- 功能: 获取区间内的任意一个随机数值
 -- 说明: 具体实现阐述 
 -- 作者: XXX
 -- 创建: yyyy-MM-dd
 -- 修改: yyyy-MM-dd XXX 修改内容描述
 -- 调用: SELECT dbo.ufn_RandNum(, );
 --==================================
 CREATE FUNCTION dbo.ufn_RandNum
 (
   @intMin INT,      -- 随机数值的最小值
   @intMax INT        -- 随机数值的最大值
 ) RETURNS INT
   --$Encode$--
 AS
 BEGIN  
   SET @intMin = ISNULL(@intMin, );
   SET @intMax = ISNULL(@intMax, );
   DECLARE @guidValue AS UNIQUEIDENTIFIER;
   SELECT TOP @guidValue = RandomGuid
   FROM dbo.vRandomGuid;
   RETURN ABS(CHECKSUM(@guidValue)) % (@intMax - @intMin + ) + @intMin;
 END
 GO 

调用以上函数的T-SQL代码如下:

 SELECT dbo.ufn_RandNum(, ) AS RandNum, dbo.ufn_RandNum(, ) AS RandNum;
 GO 

执行后的查询结果如下:

 

生成日期区间内的任意一个随机日期

    那么我们继续讲解 获取指定区间内的任意一个随机日期,不过我们要使用日期和时间的两个函数:DATEADD和DATEDIFF。使用DATEDIFF计算出日期区间的间隔值,同上的思路我们计算得到的一个随机整数值,然后通过DATEADD得到我们期望的一个随机日期。封装函数的T-SQL代码如下:

 IF OBJECT_ID(N'dbo.ufn_RandDate', 'FN') IS NOT NULL
 BEGIN
   DROP FUNCTION dbo.ufn_RandDate;
 END
 GO
 --==================================
 -- 功能: 获取日期区间内的任意一个随机日期
 -- 说明: 具体实现阐述 
 -- 作者: XXX
 -- 创建: yyyy-MM-dd
 -- 修改: yyyy-MM-dd XXX 修改内容描述
 -- 调用: SELECT @dtmRand = dbo.ufn_RandDate('--', '--');
 --==================================
 CREATE FUNCTION dbo.ufn_RandDate 
 (
   @dtmMin DATETIME,  -- 随机日期的最小值
   @dtmMax DATETIME  -- 随机日期的最大值
 ) RETURNS DATETIME
   --$Encode$--
 AS
 BEGIN
   SET @dtmMin = ISNULL(@dtmMin, '--');
   SET @dtmMax = ISNULL(@dtmMax, '--');
   DECLARE @guidVue AS UNIQUEIDENTIFIER;
   SELECT TOP @guidVue = RandomGuid 
   FROM dbo.vRandomGuid;
   -- 可以将HOUR换为DAYS
   RETURN DATEADD(HOUR, (ABS(CHECKSUM(@guidVue)) % ( + DATEDIFF(HOUR, @dtmMax, @dtmMin))), @dtmMin);
 END
 GO 

调用以上函数的T-SQL代码如下:

 SELECT dbo.ufn_RandDate('--', '--') AS RandDate, dbo.ufn_RandDate('--', '--') AS RandDate;
 GO 

执行后的查询结果如下:

 

 区间随机数获取的扩展思考

    无论是获取数值区间内的随机数值,还是日期区间内的随机日期,我们都使用了视图vRandomGuid。如果有一个连续的数值序列,我们通过查询这个数值序列,结合我们的区间数值和随机排序,也可以实现以上的效果。

    假设该数值序列为SeqDataTable(Num INT),数值区间[@intMin,@intMax],那么该数值区间任意一个随机数值的T-SQL代码如下:

 SELECT TOP Num
 FROM dbo.SeqDataTable
 WHERE Num BETWEEN @intMin AND @intMax
 ORDER BY NEWID() ASC; 

    当然也可以利用以上的数字序列SeqDataTable(Num INT),日期区间[@dtmMin,@dtmMax],那个该数字区间任意一个随机日期的T-SQL代码如下:

 SELECT TOP DATEADD(DAY, Num, @dtmMin)
 FROM dbo.SeqDataTable
 WHERE Num BETWEEN AND DATEDIFF(DAY, @dtmMax, @dtmMin)
 ORDER BY NEWID() ASC; 

 注意:以上代码无法执行成功的,也算是伪代码的。

更多精彩内容其他人还在看

SQL Server Alert发送告警邮件少了的原因

这篇文章主要为大家详细介绍了SQL Server Alert发送告警邮件少了的原因,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

分享一下SQL Server执行动态SQL的正确方式

这篇文章主要介绍了SQL Server执行动态SQL正确方式,需要的朋友可以参考下
收藏 0 赞 0 分享

SQL SERVER 中构建执行动态SQL语句的方法

这篇文章主要介绍了SQL SERVER 中构建执行动态SQL语句的方法,需要的朋友可以参考下
收藏 0 赞 0 分享

用非动态SQL Server SQL语句来对动态查询进行执行

此文章主要向大家讲述的是非动态SQL ServerSQL语句执行动态查询,在实际操作中我尝试在一个存储过程中,来进行传递一系列以逗号划定界限的值,来对结果集进行限制。但是无论什么时候,我在IN子句中使用变量,都会得到错误信息
收藏 0 赞 0 分享

SQL Server Parameter Sniffing及其改进方法

这篇文章主要介绍了SQL Server Parameter Sniffing及其改进方法,需要的朋友可以参考下
收藏 0 赞 0 分享

sqlserver实现树形结构递归查询(无限极分类)的方法

下面小编就为大家带来一篇sqlserver实现树形结构递归查询(无限极分类)的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

SQL Server Alwayson添加监听器失败的解决方法

这篇文章主要为大家详细介绍了SQL Server Alwayson添加监听器失败的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

SqlServer将查询结果转换为XML和JSON

这篇文章主要介绍了SqlServer将查询结果转换为XML和JSON的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

MSSQL批量插入数据优化详细

这篇文章主要为大家分享一下批量插入数据的方法,有时候我们需要插入大量的数据那么就需要优惠了,要不根本受不了
收藏 0 赞 0 分享

SQL Server 性能调优之查询从20秒至2秒的处理方法

这篇文章主要介绍了SQL Server 性能调优之查询从20秒至2秒的处理方法,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多