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代码如下:

 1 IF OBJECT_ID(N‘dbo.vRandomGuid‘, ‘V‘) IS NOT NULL
 2 BEGIN
 3     DROP VIEW dbo.vRandomGuid;
 4 END
 5 GO
 6
 7 --==================================
 8 -- 功能: 随机Guid视图
 9 -- 说明: 具体实现阐述
10 -- 作者: XXX
11 -- 创建: yyyy-MM-dd
12 -- 修改: yyyy-MM-dd XXX 修改内容描述
13 --==================================
14 CREATE VIEW dbo.vRandomGuid
15     --$Encode$--
16 AS
17     SELECT RandomGuid = NEWID();
18 GO
19
20 调用该视图的T-SQL代码如下:
21 SELECT TOP 1 RandomGuid
22 FROM dbo.vRandomGuid;
23 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代码如下:

 1  IF OBJECT_ID(N‘dbo.ufn_RandNum‘, ‘FN‘) IS NOT NULL
 2 BEGIN
 3     DROP FUNCTION dbo.ufn_RandNum;
 4 END
 5 GO
 6
 7 --==================================
 8 -- 功能: 获取区间内的任意一个随机数值
 9 -- 说明: 具体实现阐述
10 -- 作者: XXX
11 -- 创建: yyyy-MM-dd
12 -- 修改: yyyy-MM-dd XXX 修改内容描述
13 -- 调用: SELECT dbo.ufn_RandNum(0, 1);
14 --==================================
15 CREATE FUNCTION dbo.ufn_RandNum
16 (
17     @intMin INT,            -- 随机数值的最小值
18     @intMax INT                -- 随机数值的最大值
19 ) RETURNS INT
20     --$Encode$--
21 AS
22 BEGIN
23     SET @intMin = ISNULL(@intMin, 0);
24     SET @intMax = ISNULL(@intMax, 0);
25
26     DECLARE @guidValue AS UNIQUEIDENTIFIER;
27
28     SELECT TOP 1 @guidValue = RandomGuid
29     FROM dbo.vRandomGuid;
30
31     RETURN ABS(CHECKSUM(@guidValue)) % (@intMax - @intMin + 1) + @intMin;
32 END
33 GO

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

1 SELECT dbo.ufn_RandNum(0, 1) AS RandNum, dbo.ufn_RandNum(10, 11) AS RandNum2;
2 GO

执行后的查询结果如下:

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

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

 1 IF OBJECT_ID(N‘dbo.ufn_RandDate‘, ‘FN‘) IS NOT NULL
 2 BEGIN
 3     DROP FUNCTION dbo.ufn_RandDate;
 4 END
 5 GO
 6
 7 --==================================
 8 -- 功能: 获取日期区间内的任意一个随机日期
 9 -- 说明: 具体实现阐述
10 -- 作者: XXX
11 -- 创建: yyyy-MM-dd
12 -- 修改: yyyy-MM-dd XXX 修改内容描述
13 -- 调用: SELECT @dtmRand = dbo.ufn_RandDate(‘2007-02-01‘, ‘2007-03-01‘);
14 --==================================
15 CREATE FUNCTION dbo.ufn_RandDate
16 (
17     @dtmMin DATETIME,    -- 随机日期的最小值
18     @dtmMax DATETIME    -- 随机日期的最大值
19 ) RETURNS DATETIME
20     --$Encode$--
21 AS
22 BEGIN
23     SET @dtmMin = ISNULL(@dtmMin, ‘2000-01-01‘);
24     SET @dtmMax = ISNULL(@dtmMax, ‘2000-01-01‘);
25     DECLARE @guidVue AS UNIQUEIDENTIFIER;
26
27     SELECT TOP 1 @guidVue = RandomGuid
28     FROM dbo.vRandomGuid;
29
30     -- 可以将HOUR换为DAYS
31     RETURN DATEADD(HOUR, (ABS(CHECKSUM(@guidVue)) % (1 + DATEDIFF(HOUR, @dtmMax, @dtmMin))), @dtmMin);
32 END
33 GO

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

1 SELECT dbo.ufn_RandDate(‘2015-12-01‘, ‘2015-12-21‘) AS RandDate, dbo.ufn_RandDate(‘2016-12-01‘, ‘2016-12-21‘) AS RandDate2;
2 GO

执行后的查询结果如下:

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

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

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

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

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

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

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

 

    以后会针对数字序列有专门的详细讲解,这儿暂时作为一个扩展思考吧。

参考清单列表

https://technet.microsoft.com/zh-cn/library/ms177563(v=sql.90).aspx

https://technet.microsoft.com/zh-cn/library/ms177610(v=sql.90).aspx

https://technet.microsoft.com/zh-cn/library/ms189788(v=sql.90).aspx

https://technet.microsoft.com/zh-cn/library/ms190348(v=sql.90).aspx

http://www.cnblogs.com/chenxizhang/archive/2009/06/26/1511898.html

博友如有其他更好的解决方案,也请不吝赐教,万分感谢。

 

时间: 2024-11-17 06:49:05

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

SQL Server中,with as使用介绍

一.WITH AS的含义      WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候,是为了让SQL语句的可读性更高些,也有可能是在UNION ALL的不同部分,作为提供数据的部分.  特别对于UNION ALL比较有用.因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,所以可以使用WITH AS短语,则只要执行一遍即可.如果WITH AS短语

SQL SERVER 中的 object_id()函数

在数据库中有一个系统表sysobjects,里面存储了数据库各个对象的信息.可以查询下看看结果.可以看出每个对象都有一个ID,这个表存储了表,存储过程,触发器,视图等相关信息.注意:字段没有. object_id就是根据对象名称返回该对象的id.  object_name是根据对象id返回对象名称. select object_id(对象名)等同于:  select id from sysobjects where name=对象名 select object_name(id号)等同于:  se

sql server中的开窗函数over、视图、事物

一.开窗函数over的作用有两个: 1.排序order by,row_number,翻页 2.划区partition by,结合聚合函数针对某部分数据进行汇总 翻页的sql server 语句: select * from ( select *,row_number() over( order by id) as num from 表名) as t where t.num>6 and t.num<10 二.视图:用于存储一个select语句.并不是存储数据的一个容器. create view

sql server中的charindex函数用法解析(在一段字符中搜索字符或者字符串-----返回expression1在expression2出现的位置;反之,返回0)

https://blog.csdn.net/xinghuo0007/article/details/70651358 知识点一:charindex()语法 CHARINDEX ( expression1 , expression2 [ , start_location ] ) 解析: expression1 必需 ---要查找的子字符串 expression2 必需 ---父字符串 start_location 可选 ---指定从父字符串开始查找的位置,默认位置从1开始 知识点二: charin

Sql Server 中利用Convert 函数转换Datetime 到 String

CONVERT(varchar(10), date, 23) 1    02/22/06            CONVERT(varchar(10), date, 1) 0 Feb 22 2006 4:26PM CONVERT(CHAR(19), CURRENT_TIMESTAMP, 0) 1 02/22/06 CONVERT(CHAR(8), CURRENT_TIMESTAMP, 1) 2 06.02.22 CONVERT(CHAR(8), CURRENT_TIMESTAMP, 2) 3 2

用java实现sql server中的datediff函数

1 /** 2 * 计算两个时间的相差值, 可以计算相差的天数, 年数, 月份数, 分钟数, 秒数 3 * 4 * @param dateType 要得到的两个时间之间差值的类型, 例如要得到两个时间差的天数?还是小时数? 5 * @param startDate 开始时间 6 * @param endDate 结束时间 7 * @return (结束时间-开始时间) 之间的 dateType值 8 */ 9 public static int datediff(String dateType,

MS SQL server中的isnull函数

一.ISNULL语法格式 ISNULL ( check_expression , replacement_value ) 二.参数简介 check_expression:将被检查是否为 NULL的表达式,check_expression可以是任何类型的. replacement_value:在 check_expression 为 NULL时将返回的表达式,replacement_value 必须与 check_expresssion 具有相同的类型. 三.返回值 返回与 check_expre

SQL Server 中的排名函数与使用场景

1.RowNumber() Over (oder by.....)   在需要对某个不连续ID的表进行排序时使用 2.ROW_NUMBER() over(PARTITION by ...... order by ......)  在需要对某个表先进行分区时,再在分区内进行排序操作时使用 3.RANK() over(order by ......) 在需要对某个字段进行同名排序时使用(不考虑并列) 4.DENSE_RANK() over(order by ......) (同上,但是考虑并列名次)

SQL Server 中WITH (NOLOCK)浅析

原文:SQL Server 中WITH (NOLOCK)浅析 概念介绍 开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其实是表提示(table_hint)中的一种.它等同于 READUNCOMMITTED . 具体的功能作用如下所示(摘自MSDN): 1: 指定允许脏读.不发布共享锁来阻止其他事务修改当前事务读取的数据,其他事务设置的排他锁不会阻碍当前事务读取锁定数据.允许脏读可能产生较多的并发操作,但其代价是读取以后会被其他事务回滚的数据修改.这可能会使您的