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.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM