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

工作中会遇到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;

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

时间: 2024-08-01 01:20:29

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

SQL Server中追踪器Trace的介绍和简单使用

原文:SQL Server中追踪器Trace的介绍和简单使用 一.What is Trace? 对于SQL Profiler这个工具相信大家都不是很陌生,没用过的朋友可以在SQL Server Management Studio>工具>SQL Server Profiler处使用.这个工具是用来监控SQL,存储过程的执行,用户登录等等信息.但这个工具只是一个GUI,他的本质就是Trace.下面是Trace的架构:    数据库引擎会产生一系列事件,然后各个trace可以去订阅自己感兴趣的事件,

关于SQL Server中的死锁详解介绍(1/3)

 一些基础知识     要理解SQL Server中的死锁,更好的方式是通过类比从更大的面理解死锁.比如说一个经典的例子就是汽车(主体)对于道路(资源)的征用,如图1所示. 对于死锁的直观理解      在图1的例子中,每队汽车都占有一条道路,但都需要另外一队汽车所占有的另一条道路,因此互相阻塞,谁都无法前行,因此造成了死锁.由这个简单的例子可以看出,发生死锁需要四个必要条件,如下: 1)互斥条件:     主体对于资源是独占的,图1中每条汽车道只能跑一队汽车,不能跑第二队.  2)请求和等待条

SQL Server 中 RAISERROR 的用法详细介绍_mssql2005

 SQL Server 中 RAISERROR 的用法 raiserror 的作用: raiserror 是用于抛出一个错误.[ 以下资料来源于sql server 2005的帮助 ] 其语法如下: RAISERROR ( { msg_id | msg_str | @local_variable } { ,severity ,state } [ ,argument [ ,...n ] ] ) [ WITH option [ ,...n ] ] 简要说明一下:   第一个参数:{ msg_id |

SQL server中字符串逗号分隔函数分享_MsSql

继SQl -Function创建函数数据库输出的结果用逗号隔开,在开发中也有许多以参数的形式传入带逗号字条串参数(数据大时不建议这样做) 例:查找姓名为"张三,李二" 的数据此时在数据库里就要对此参数做处理如图: 函数代码如下 CREATE FUNCTION [dbo].[fnSplitStr] ( @sText NVARCHAR(Max), @sDelim CHAR(1) ) RETURNS @retArray TABLE ( value VARCHAR(100) ) AS BEGI

SQL Server中的Rounding函数

问题 最近我试着在自己的应用中使用四舍五入的值,我和我的用户在报表应用中的 计算问题存在分歧.所有的代码都在T-SQL中,但是我认为报表问题与数据类型和 向下取整或向上取整规则关系密切.请问您有没有这方面的高见?我想看到一些带 有不同编码选项的例子. 专家解答 如果不理解基本的数据类型和四舍五入函数,那么你就可能误解四舍五入.由 于数据类型的差异(比如integer,float, decimal等等),四舍五入后的值可能 会不同.另外,由于在计算中使用的SQL Server舍入函数(ROUND(

SQL server中字符串逗号分隔函数分享

继SQl -Function创建函数数据库输出的结果用逗号隔开,在开发中也有许多以参数的形式传入带逗号字条串参数(数据大时不建议这样做) 例:查找姓名为"张三,李二" 的数据此时在数据库里就要对此参数做处理如图: 函数代码如下 CREATE FUNCTION [dbo].[fnSplitStr] ( @sText NVARCHAR(Max), @sDelim CHAR(1) ) RETURNS @retArray TABLE ( value VARCHAR(100) ) AS BEGI

Sql Server中的DBCC命令详细介绍_MsSql

     今天研发中心办年会,晚上就是各自部门聚餐了,我个人喜欢喝干红,在干红中你可以体味到那种酸甜苦辣...人生何尝不是这样呢???正好ceo从美国带了干红回来,然后我就顺道开心的过了把瘾....一个字...爽....喝着有点多...到现在头还疼....回来地铁上想这个周末忙着找房子,书一点都没看,也没在博客上接着忽悠,想起了上篇博客有个哥们说普及普及DBCC,虽然有点迷迷糊糊的...看能不能写出点新花样....不管学什么语言,还是数据库,你得看的比人家深一层...最可悲的就是停留的在表层,这

缩小SQL Server中日志文件的方法介绍

前几天也碰到日志文件过大的问题,数据库实际大小为600M, 日志文件实际大小为33M, 但日志文件占用空间为2.8G!!! 试了多种方式,SHIRNK DATABASE, TRUNCATE LOG FILE, 都没办法将文件缩小.无论如何,这应该算SQL SERVER的一个BUG吧. 后来找到下面的代码,就可以将日志文件缩小到自己想要的大小了.把代码COPY到查询分析器里,,然后修改其中的3个参数(数据库名,日志文件名,和目标日志文件的大小),运行即可(我已经用过多次了) SET NOCOUNT

Sql Server中的系统视图详细介绍_MsSql

本来想这个系列写点什么好呢,后来想想大家作为程序员,用的最多的莫过于数据库了,但是事实上很多像我这样工作在一线的码农,对sql都一知半解,别谈优化和对数据库底层的认识了,我也是这样...  一:那些系统视图 1. 系统视图是干什么呢? 从名字上看就知道,系统视图嘛?猜的不错的话,就是存放一些sqlserver系统的一些信息,很好,恭喜你,答对了.  2. 都定义在哪呢?  为了让你眼见为实,下面截图看看,从截图中你可以看到,不管是"系统数据库"还是"用户数据库"都是