SQL Cursor生成唯一的非顺序PINS

时间:2016-10-13 21:56:40

标签: sql-server loops random cursor unique

我正在尝试为一群新员工生成非连续的唯一PIN码。 这是它应该如何工作: 1.游标应该从表B中获取所有新员工 2.为每位新员工生成新的独特引脚 3.检查表A中是否已存在新生成的PIN 4.如果是,请重复步骤2,直到我们为所有新员工获取唯一的PIN 5.将新员工编号和PIN插入表A

在表A上,字段为PIN,Employee_Number,日期

我尝试使用游标逐个插入每个新的emp和他的PIN,以便检查每个插入的唯一性:

这只循环一次并停止,有人能告诉我我缺少的东西

 DECLARE 
    @EmpNo             VARCHAR(50), 
    @Pin               INT, 
    @today             DATETIME,
    @Upper             INT,
    @Lower             INT,
SET @Lower = 100000 ---- The lowest random number allowed
SET @Upper = 999999 ---- The highest random number allowed

DECLARE cur CURSOR FOR 

SELECT   
       Employee_Number, 
       (ROUND(((@Upper - @Lower -1) * RAND() + @Lower), 0))as PIN, 
       GETDATE()
FROM     TableB 
WHERE    Employee_Number NOT IN (SELECT Employee_Number FROM TableA)


OPEN cur
FETCH NEXT FROM cur INTO @EmpNo, @Pin, @Today

WHILE @@FETCH_STATUS=0

BEGIN    

         INSERT INTO TableA (PIN, Employee_Number, Date)
         SELECT @Pin, @EmpNo, @Today


FETCH NEXT FROM cur INTO @Pin, @EmpNo, @Today
END

CLOSE cur
DEALLOCATE cur

2 个答案:

答案 0 :(得分:0)

你不需要光标。另外,最好使用newid()生成随机数而不是rand()

INSERT INTO TableA (PIN, Employee_Number, Date)
SELECT pin = @Lower 
           + (   abs(convert(bigint,convert(varbinary(20),newid()))) 
               % (@Upper - @Lower + 1) 
             ),
       Employee_Number,
       GETDATE()
FROM   TableB 
WHERE  Employee_Number NOT IN (SELECT Employee_Number FROM TableA)

编辑:

处理独特的引脚,不使用光标的解决方案是保留所有可能引脚的表。

create table pin
(
    pin         int primary key,
    is_used     bit default 0
)

使用recursive cte

生成引脚
; with num as
(
    -- anchor member
    select  pin = @Lower

    union all

    -- recursive member
    select  pin = pin + 1
    from    num
    where   pin < @Upper
)
insert into pin (pin) 
select  pin
from    num

然后当您需要将销分配给员工时

; with emp as
(
    select  Employee_Number, rn = row_number() over (order by Employee_Number)
    from    TableA a
    where   not exists
            (
                select  *
                from    TableB b
                where   b.Employee_Number   = a.Employee_Number
            )
),
pin as
(
    -- get unused pin, order it randomly using newid()
    select  pin, rn = row_number() over (order by newid())
    from    pin
    where   is_used = 0
)
insert into #TableB (Employee_Number, pin)
select  e.Employee_Number, p.pin
from    emp e
        inner join pin p    on  e.rn    = p.rn

之后更新了针脚表中的is_used列

update  p
set     is_used = 1
from    TableB b
        inner join #pin p   on  b.pin   = p.pin
where   p.is_used   = 0

答案 1 :(得分:0)

另一种方法可能如下。

注意@EmpTable是一个演示版EmpTable(为您的环境删除@)

1)cte0生成一个10行的基本计数表

2)cteR将cte0扩展为1,000行并添加随机字符串(NewID())

3)cteI将cteR转换为INT(不超过6位)

4)更新适用于所有NULL PINS

Declare @EmpTable table (Employee_Number int,PIN int)
Insert Into @EmpTable values
(1,100288),(2,651701),(3,823700),
(4,NULL),(5,NULL)

Declare @Lower int=100000,@Upper int = 999999

 ;with cte0(N)   As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N))
     , cteR(R)   As (Select Distinct R=cast(NewID() as varchar(50)) From cte0 N1, cte0 N2, cte0 N3, cte0 N4) 
     , cteI(R,N) As (Select Distinct R,cast(Left(cast(abs(cast(Hashbytes('MD5',R) as int)) as varchar(25)),6) as int) From cteR R) 
Update @EmpTable Set PIN = B.N
 From  @EmpTable A
 Join  (
         Select RowNr=(Select min(Employee_Number)-1 From @EmpTable Where PIN is NULL)+Row_Number() over (Order By R)
               ,N 
          From  cteI 
          Where N Between @Lower and @Upper
            and N not in (Select Distinct PIN From @EmpTable Where PIN is not NULL)
        ) B on A.Employee_Number=B.RowNr and PIN is null


Select * from @EmpTable

更新了EmpTable

Employee_Number PIN
1               100288   -- Same as Original
2               651701   -- Same as Original
3               823700   -- Same as Original
4               118844   -- New Random PIN
5               677855   -- New Random PIN