sql 生成随机数 以及不重复随机数

背景:想在表中随机取10条记录,让取出来的数据不重复(表中必须是有个递增列,且递增从1开始间隔为1)。 

数据表:

CREATE TABLE testable
(
id INT  IDENTITY(1,1),
myname  NVARCHAR(1000),
insertedTime DATETIME DEFAULT SYSDATETIME()
)

 

表中共有100条数据,如下

image 省略……

 

 

 

 

1.     首先想到的是MSSQL自带的newid()

 

采用这种方法时,需要将表中所有记录与newid()生成的值进行比较从而进行排序。因此,如果表中的记录较多,操作会非常缓慢。

image

 

 

 

USE  Gift163DB

go

SELECT  TOP  14  * FROM  dbo.testable   ORDER BY NEWID()

 

缺点:1. 取出的10条数据会出现重复      2.当数据表数据很多的时候,速度将很慢 (每次重新计算newid)

 

 

 

2. 自定义函数返回一个表,表中记录的是随机生成的N个id值。

 

1)rand()生成随机数        rand()*count,CEILING,floor用法 

2)如果临时表中无此数据,则放入,否则重新生成

3)直到N条记录已经生成

 

注意:标量函数function内不能出现rand()方法,变通下生成个view  v_random,然后在函数内调用 v_random获取随机数

create view v_random

AS

   

   select CEILING(rand()*51) as random    --注意51,生成的是1到51之间的数字,因为事先知道数据库中有51条记录

go

 

 

自定义函数代码如下:

 

ALTER FUNCTION  randomIntStringWithCommaSplit(@counts int) –counts 表明返回的个数

          
RETURNS @t TABLE (filed1 int)  --返回表@t,有个int类型的 field列

AS

BEGIN

  

  DECLARE @randomInt INT

  DECLARE @i INT

  SET @i=0

        WHILE @i<@counts

        BEGIN

          

                 select @randomInt= random FROM v_random

          

          --不能是 SET @randomInt=SELECT random FROM v_random

          IF NOT EXISTS(SELECT TOP 1 * FROM @t WHERE filed1=@randomInt)

           BEGIN

             INSERT INTO @t VALUES (@randomInt)

             SET @i=@i+1

           END

        END

  RETURN 

  

END

 

上面函数返回的是一个表类型,表中有个int字段,存放要查找的N个不同的keyId  (keyId为要查找表的递增列,且递增为1,从1开始递增)

所以返回的表中存放的数据是 dbo.Articles中的id列的值。

 

 

使用:调用上面的自定义函数返回10个不重复的id

 

SELECT * FROM randomIntStringWithCommaSplit(10)

 

下面是几次的执行结果,可以看到每个结果中都不存在重复的值(fidled1为临时表的唯一列)

image image image image image

 

 

最后通过  select * from table  where id in  randomIntStringWithCommaSplit(10) ,这样就可以从table中随机取出10条不重复的数据来了。

 

 

 

 

3.存储过程取不重复的数据

 

--dbo.getRandomDataFromTable
--输入参数  @tableName  nvarchar(100),--表名
---@dataCount  nvarchar(100)--取N条数据

 

输出结果集:列id,存放N条要查询的数据

USE Gift163DB

GO

IF OBJECT_ID ( 'dbo.getRandomDataFromTable', 'P' ) IS NOT NULL 

    DROP PROCEDURE dbo.getRandomDataFromTable;

GO

CREATE PROC  [dbo].[getRandomDataFromTable]

@tableName  nvarchar(100),

@dataCount  nvarchar(100)

AS

BEGIN

  --SET NOCOUNT ON;

    

    DECLARE @t TABLE (id INT)   --临时表

    DECLARE @i  INT             --临时变量

    DECLARE @randomInt INT      --每次随机生成的整数

    DECLARE @tableCount INT     --表的行数

    

    --先获取表中最大数据的id

   EXEC(  'SELECT '+@tableCount+'=COUNT(*) FROM  '+@tableName+'')

    SET @i=0

    WHILE @i<@dataCount

    BEGIN

      SELECT @randomInt=CEILING(RAND()*@tableCount)

      

      IF NOT EXISTS(SELECT TOP 1 * FROM @t)

      BEGIN

          

          INSERT INTO @t VALUES (@randomInt)

          SET @i=@i+1

      END

      

    END

    

    

    --打印出取出的表的id

    SELECT * FROM @t

    

       

  

END

Go

 

 

生成测试数据100条

USE Gift163DB

GO

if exists (select 1

            from  sysobjects

           where  id = object_id('testable')

            and   type = 'U')

   drop table testable

go

CREATE TABLE testable

(

id INT  IDENTITY(1,1),

myname  NVARCHAR(1000),

insertedTime DATETIME DEFAULT SYSDATETIME()

)

//插入100条数据

DECLARE @i INT

SET @i=1

WHILE @i<100

BEGIN

  INSERT INTO tesTable (myname) VALUES ('我的名字是'+CONVERT(NVARCHAR, @i) )   --将 varchar 值 '我的名字是' 转换成数据类型 int 时失败。

  SET @i=@i+1

End

  

 

 

调用上面的存储过程从表testable取10条不重复id

 

 

USE Gift163DB

go

 exec    getRandomDataFromTable  'testable',10

 

 

 

image image image

自定义的存储过程不会出现重复的记录

 

 

 

 

 

4.改进的存储过程,最终存储过程

 

输入参数3个:表名,表的递增列名 , 要取的N条数据

 

USE Gift163DB

GO

IF OBJECT_ID ( 'dbo.getRandomDataFromTable', 'P' ) IS NOT NULL 

    DROP PROCEDURE dbo.getRandomDataFromTable;

GO

CREATE PROC  [dbo].[getRandomDataFromTable]

@tableName  nvarchar(100),

@identityKey NVARCHAR(100),

@dataCount  nvarchar(100)

AS

BEGIN

  --SET NOCOUNT ON;

   

    --DECLARE @t TABLE (id INT)   --临时表

    DECLARE @i  INT             --临时变量

    DECLARE @randomInt INT      --每次随机生成的整数

    DECLARE @tableCount INT     --表的行数

   

   

    

    --先获取表中最大数据的id

   DECLARE @str NVARCHAR(3000)

   SET @str='SELECT @tableCount=COUNT(*) FROM  '+@tableName

   exec sp_executesql @str, N'@tableCount int output', @tableCount output

  

  

   create TABLE #sdf (id int)

   

   

   

    SET @i=0

    WHILE @i<@dataCount AND @i<@tableCount

    BEGIN

      SELECT @randomInt=CEILING(RAND()*@tableCount)

      

      IF NOT EXISTS(SELECT TOP 1 * FROM #sdf WHERE id=@randomInt)

      BEGIN

          

          INSERT INTO #sdf VALUES (@randomInt)

          SET @i=@i+1

      END

      

    END

    

     

    --取出数据

    DECLARE @str2 NVARCHAR(2000)

    

    SET @str2=' SELECT  * FROM '+@tableName

        +' where '+@identitykey

        +' in '

        +' (select id from #sdf )'

        

    

    

    

    PRINT @str2

    --select id from  @t

    

    EXEC (@str2)

    --exec sp_executesql @str2,N'@t TABLE',@t OUTPUT

       

       

   

     

  

END

 

调用存储过程:随机取10条数据

image image

 

最终的存储过程不管你随机取多少条数据(只要每次取的数据数目小于表中行数) 就可以保证每次取的数据不会重复。当然前提是,取的表必须有个递增列,而且以1开始,递增1.

你可能感兴趣的:(sql)