2009-11-01 2 views
1

각 호출마다 단일 임의 번호를 얻어야하는 프로 시저를 작성하고 있습니다. 이 절차는 .net 웹 서비스에서 호출됩니다.SqlServer Rand() 질문

저는 이것을 rand()를 사용하여 구현하려고했습니다. 그러나 밀리 초 내에 저장 프로 시저를 여러 번 호출하면 동일한 임의의 숫자가 생성된다는 점에서 많은 충돌이 발생합니다. 후속 호출 사이에 약 20 또는 30 밀리 초의 공간이 있으면 제대로 작동하는 것 같습니다.

rand()가 SqlServer에 의해 저장된 프로 시저 호출마다 다시 시드 된 것처럼 보입니다. 내가 이해할 수있는 한 것은 난수 생성기를 한 번 시드해야하고 하나가 rand에 대한 각 호출을 다시 시드하는 경우 의사 난수 시퀀스의 좋은 시퀀스를 얻지 못하기 때문에 이것이 문제라는 것입니다. 또한 1 ~ 2 밀리 초 내에있는 동일한 sp에 대한 호출은 동일한 값으로 시드됩니다.

다음은 저장 프로 시저의 문입니다.

DECLARE @randomNumber char(9) 

SET @randomNumber = RIGHT('00000' + CAST(CAST(rand()*100000 AS INT) AS VARCHAR(5)),5) 
+ RIGHT('00000' + CAST(CAST(rand()*10000 AS INT) AS VARCHAR(4)),4) 

아무에게도이 문제를 해결하기위한 제안이 있습니까?

한 번 시드 된 임의의 번호 생성기를 작성해야하며 전화를 통해 테이블에 상태를 저장해야합니까? SQL Server는 rand()를 어떻게 시드합니까? 정말 무작위입니까, 아니면 별도의 연결에서 서로 1 ~ 2 밀리 초 내에 sp를 호출해도 충돌을 일으키는 동일한 시드가 포함될 것입니까? 당신의 예에서

+1

CLR 저장 프로 시저를 작성하고 .NET Framework의 난수 기능을 사용하려고 시도 했습니까? – Kuberchaun

답변

9

는 SQL Server 2008을 사용하는 경우, 당신은 CRYPT_GEN_RANDOM() 함수를 사용할 수 있습니다.

다음은 BOL 기사에 대한 링크가의

SELECT CAST(RIGHT(CAST(CAST(CRYPT_GEN_RANDOM(1) AS INT) AS VARCHAR(100)), 1) AS INT) 

: 이것은 하나의 쿼리 실행에 임의의 숫자의 수백만을 계산하기 위해 노력하고 있었다 및 파종 문제가없는 경우에도 모든 행에 대한 데이터를 무작위 것 http://msdn.microsoft.com/en-us/library/cc627408.aspx

+1

+1. 이것은 나에게 새로운 것이다. 아주 좋아. 나는 그것을 좋아한다. – gbn

5

, CHAR (9)에 대해, ABS(CHECKSUM(NEWID())) % 9999

그러나 함께 rand()*10000 교체 ...

SELECT RIGHT('000000000' + CAST(ABS(CHECKSUM(NEWID()) % 999999999) AS char(9), 9) 

이 씨앗 무작위 RAND

RAND(CHECKSUM(NEWID())) 

편집 :

참고, RAND가 SQL Server에 잘못 구현되었습니다. 사용하지 마십시오.

+0

+! 작동하지만 newid() 또는 체크섬 (newid())의 배포에 대한 보증이 있는지 궁금합니다. newid()의 계산에 MAC 주소가 사용되지 않았습니까? – Andomar

+0

newid = GUID, 동일한 통계. CHECKSUM = 부호있는 32 비트 = 40 억 – gbn

+0

지금까지 가장 좋은 솔루션처럼 보입니다. 그러나 RNGCryptoServiceProvider를 사용하는 clr 저장 프로 시저에 대해서도 살펴 보았습니다. –

0

RAND() function에는이를 위해 사용할 수있는 선택적 시드 매개 변수가 있습니다. 마지막으로 생성 된 무작위 값을 다음 번 rand() 호출의 시드로 전달하면 새 난수를 얻을 수 있습니다.

rand()가 부동 소수점을 반환하는 반면 시드가 정수인 것을 나타내는 gbn에게 감사드립니다. 그 지식으로, 여기에 실례가 있습니다!

create table RandomNumber (number float) 
insert into RandomNumber values (rand()) 

그런 다음 임의의 숫자를 잡고 트랜잭션에 새 번호를 저장 :

declare @new float 
begin transaction 
select @new = rand(-2147483648 + 4294967295 * number) 
    from RandomNumber with (updlock, holdlock) 
update RandomNumber set number = @new 
commit transaction 
print 'Next bingo number is: ' + cast(cast(@new*100 as int) as varchar) 

중 SQL 서버 정수 -2147483648과 2147483647 사이에서 변화하고, 임의의 숫자가 있습니다 먼저 테이블을 생성 0.0 ~ 1.0 사이에서 부동합니다. 따라서 -2147483648 + 4294967295 * number은 사용 가능한 정수의 전체 범위를 포함해야합니다.

트랜잭션을 통해 한 번에 하나의 연결 만 읽고 새 번호를 저장합니다. 따라서 SQL Server에 대한 다른 연결에서도 숫자는 임의적입니다. (그런데, 나는 gbn의 대답에 찬성했다. 훨씬 쉬워 보였다.)

+0

재미있는 생각이지만,이 상태를 테이블에 저장하고 sp의 각 호출마다 찾아야합니다. 비싸 보입니다. 또한이 방법으로 시드를 설정하면 좋은 의사 랜덤 시퀀스가 ​​생성됩니까? –

+1

@Andomar : RAND는 int 시드를 취하므로 각 itertion에 대해 동일한 시드를 시드합니다. 내 오래된 대답을 참조하십시오 : http://stackoverflow.com/questions/1038681/sql-random-number-not-working/1354125#1354125 – gbn

0

당신은 종자로 사용하는 독특한 nunbers을 만들기위한 단지 식별자 필드와 테이블을 사용할 수 있습니다

declare 
    @randomNumber char(9), 
    @seed1 int, 
    @seed2 int 

insert into SeedTable() values() 
set @seed1 = scope_identity() 

insert into SeedTable() values() 
set @seed2 = scope_identity() 

set @randomNumber = right('00000' + 
    cast(cast(rand(@seed1) * 100000 as int) as varchar(5)), 5) + 
    right('00000' + 
    cast(cast(rand(@seed2) * 10000 as int) as varchar(4)), 4) 

if (@seed2 > 10000) truncate table SeedTable 
+0

SeedTable이라는 테이블을 만들려고 했습니까? – Andomar

+0

@Andomar : 네, 그게 제가 말하고있는 식별자를 가진 테이블입니다. – Guffa

+0

@ Guffy : 테이블을 잘라내어 ID 열을 재설정 하시겠습니까? – Andomar