Programing

TSQL Select의 각 행에 대해 난수를 어떻게 생성합니까?

lottogame 2020. 3. 12. 08:08
반응형

TSQL Select의 각 행에 대해 난수를 어떻게 생성합니까?


내 테이블의 각 행마다 다른 임의의 숫자가 필요합니다. 다음의 명백한 코드는 각 행에 대해 동일한 임의의 값을 사용합니다.

SELECT table_name, RAND() magic_number 
FROM information_schema.tables 

이 중 INT 또는 FLOAT를 얻고 싶습니다. 이야기의 나머지 부분은이 난수를 사용하여 알려진 날짜에서 임의의 날짜 오프셋을 생성합니다 (예 : 시작 날짜에서 1-14 일 오프셋).

Microsoft SQL Server 2000 용입니다.


SQL Server-Set based random numbers살펴보십시오 . 자세한 설명이 나와 있습니다.

요약하면 다음 코드는 정규화 된 분포를 사용하여 0에서 13 사이의 난수를 생성합니다.

ABS(CHECKSUM(NewId())) % 14

범위를 변경하려면 식 끝에 숫자를 변경하십시오. 양수와 음수를 모두 포함하는 범위가 필요한 경우 특히주의하십시오. 잘못하면 숫자 0을 두 번 계산할 수 있습니다.

방의 수학 너트에 대한 작은 경고 :이 코드에는 약간의 편견이 있습니다. CHECKSUM()sql Int 데이터 유형의 전체 범위에서 균일하거나 최소한 (편집자) 테스트에서 볼 수있는 정도의 숫자가됩니다. 그러나 CHECKSUM ()이 해당 범위의 맨 끝에 숫자를 생성 할 때 약간의 편차가 있습니다. 가능한 최대 정수와 원하는 최대 크기 (이 경우 14)의 크기의 마지막 정확한 배수 사이의 숫자를 얻을 때마다 그 결과는 범위의 나머지 부분보다 선호됩니다. 마지막 배수는 14의 배수입니다.

예를 들어, Int 유형의 전체 범위가 19에 불과하다고 가정하십시오. 19는 보유 할 수있는 가장 큰 정수입니다. CHECKSUM ()의 결과가 14-19 인 경우 결과 0-5에 해당합니다. CHECKSUM ()이 생성 할 가능성이 두 배이기 때문에이 숫자는 6-13보다 많이 선호됩니다. 이것을 시각적으로 설명하는 것이 더 쉽습니다. 다음은 가상 정수 범위에 대한 가능한 전체 결과 집합입니다.

체크섬 정수 : 12 34 5678 9 10 11 12 1314 15 16 17 18 19
범위 결과 : 12 34 5678 9 10 11 12 1103 34 5

여기에서 다른 것보다 더 많은 숫자를 생성 할 수있는 기회가 더 많다는 것을 알 수 있습니다 : 편향. 고맙게도 Int 유형의 실제 범위는 훨씬 큽니다. 그래서 대부분의 경우 바이어스를 거의 감지 할 수 없습니다. 그러나 심각한 보안 코드를 위해이 작업을 수행하는 경우 알고 있어야합니다.


단일 배치에서 여러 번 호출되면 rand ()는 동일한 숫자를 반환합니다.

시드 인수로 convert ( varbinary, newid())를 사용하는 것이 좋습니다 .

SELECT table_name, 1.0 + floor(14 * RAND(convert(varbinary, newid()))) magic_number 
FROM information_schema.tables

newid() 동일한 배치 내에서도 호출 될 때마다 다른 값을 반환하도록 보장되므로 시드로 사용하면 rand ()가 매번 다른 값을 지정하도록 프롬프트합니다.

1에서 14 사이의 임의의 정수를 얻도록 편집되었습니다.


RAND(CHECKSUM(NEWID()))

위의 0과 1 사이의 (의사) 난수를 제외하고 생성합니다. 선택에 사용되는 경우 각 행의 시드 값이 변경되므로 각 행에 대해 새로운 난수를 생성합니다 (단, 행당 고유 한 숫자를 생성 할 수는 없습니다).

상한을 10으로 조합 한 예 (숫자 1 ~ 10 생성) :

CAST(RAND(CHECKSUM(NEWID())) * 10 as INT) + 1

Transact-SQL 설명서 :

  1. CAST(): https://docs.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql
  2. RAND(): http://msdn.microsoft.com/en-us/library/ms177610.aspx
  3. CHECKSUM(): http://msdn.microsoft.com/en-us/library/ms189788.aspx
  4. NEWID(): https://docs.microsoft.com/en-us/sql/t-sql/functions/newid-transact-sql

1000에서 9999 사이의 난수 생성 :

FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000)

"+1"-상한값 포함 (이전 예의 경우 9999)


이전 질문에 대답했지만이 답변은 이전에 제공되지 않았으므로 검색 엔진을 통해이 결과를 찾는 사람에게 유용 할 것입니다.

SQL Server 2008 CRYPT_GEN_RANDOM(8)에는 CryptoAPI를 사용하여 암호화 적으로 강력한 난수를 생성하는 새로운 기능이 도입되었으며 로 반환됩니다 VARBINARY(8000). 설명서 페이지는 다음과 같습니다. https://docs.microsoft.com/en-us/sql/t-sql/functions/crypt-gen-random-transact-sql

임의의 숫자를 얻으려면 간단히 함수를 호출하여 필요한 유형으로 캐스팅하면됩니다.

select CAST(CRYPT_GEN_RANDOM(8) AS bigint)

또는 float-1과 +1 사이 를 얻으려면 다음과 같이 할 수 있습니다.

select CAST(CRYPT_GEN_RANDOM(8) AS bigint) % 1000000000 / 1000000000.0

Rand () 함수는 테이블 SELECT 쿼리에 사용되는 경우 동일한 난수를 생성합니다. Rand 함수에 시드를 사용하는 경우에도 동일하게 적용됩니다. 다른 방법은 다음을 사용하는 것입니다.

SELECT ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) AS [RandomNumber]

여기 에서 정보를 얻었습니다 . 문제를 잘 설명합니다.


RAND 함수에 시드로 전달할 수있는 각 행에 정수 값이 있습니까?

1과 14 사이의 정수를 얻으려면 이것이 효과가 있다고 생각합니다.

FLOOR( RAND(<yourseed>) * 14) + 1

시드가 매번 "동일한"임의의 데이터를 생성하도록 시드를 보존해야하는 경우 다음을 수행 할 수 있습니다.

1. select rand ()를 리턴하는 뷰를 작성하십시오.

if object_id('cr_sample_randView') is not null
begin
    drop view cr_sample_randView
end
go

create view cr_sample_randView
as
select rand() as random_number
go

2.보기에서 값을 선택하는 UDF를 작성하십시오.

if object_id('cr_sample_fnPerRowRand') is not null
begin
    drop function cr_sample_fnPerRowRand
end
go

create function cr_sample_fnPerRowRand()
returns float
as
begin
    declare @returnValue float
    select @returnValue = random_number from cr_sample_randView
    return @returnValue
end
go

3. 데이터를 선택하기 전에 rand () 함수를 시드 한 후 select 문에서 UDF를 사용하십시오.

select rand(200);   -- see the rand() function
with cte(id) as
(select row_number() over(order by object_id) from sys.all_objects)
select 
    id,
    dbo.cr_sample_fnPerRowRand()
from cte
where id <= 1000    -- limit the results to 1000 random numbers

RAND (seedInt)에서 시드 값을 사용해보십시오. RAND ()는 명령문 당 한 번만 실행되므로 매번 같은 숫자가 표시됩니다.


정수가 아닌 임의의 고유 식별자 인 경우 사용할 수 있습니다 newid()

SELECT table_name, newid() magic_number 
FROM information_schema.tables

각 행마다 RAND ()를 호출해야합니다. 여기 좋은 예가 있습니다

https://web.archive.org/web/20090216200320/http://dotnet.org.za/calmyourself/archive/2007/04/13/sql-rand-trap-same-value-per-row.aspx


select round(rand(checksum(newid()))*(10)+20,2)

여기서 난수는 20에서 30 사이 round입니다. 소수점 이하 두 자리를 최대 값으로 지정합니다.

음수를 원하면 함께 할 수 있습니다.

select round(rand(checksum(newid()))*(10)-60,2)

그러면 최소값은 -60이되고 최대 값은 -50이됩니다.


newid ()를 선택하십시오

아니면이 선택 binary_checksum (newid ())


내가 선택한 "답변"에서 때때로 문제는 분포가 항상 고르지 않다는 것입니다. 많은 행 사이에 임의의 1-14 분포가 매우 균일 해야하는 경우 이와 같은 작업을 수행 할 수 있습니다 (데이터베이스에 511 개의 테이블이 있으므로 작동합니다. 임의의 수 범위보다 행이 적을 경우 작동하지 않습니다. 잘):

SELECT table_name, ntile(14) over(order by newId()) randomNumber 
FROM information_schema.tables

이런 종류의 숫자는 숫자를 순서대로 유지하고 다른 열을 무작위 화한다는 점에서 일반적인 무작위 솔루션과 반대입니다.

데이터베이스에 511 개의 테이블이 있습니다 (Information_schema에서 선택한 b / c에만 해당됨). 이전 쿼리를 가져 와서 임시 테이블 #X에 넣은 다음 결과 데이터에서이 쿼리를 실행합니다.

select randomNumber, count(*) ct from #X
group by randomNumber

이 결과를 얻었고 내 임의의 숫자가 많은 행에 균등하게 분포되어 있음을 보여줍니다.

여기에 이미지 설명을 입력하십시오


select ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) as [Randomizer]

항상 나를 위해 일했다


다음과 같이 쉽습니다.

DECLARE @rv FLOAT;
SELECT @rv = rand();

그리고 이것은 0-99 사이의 임의의 숫자를 테이블에 넣습니다.

CREATE TABLE R
(
    Number int
)

DECLARE @rv FLOAT;
SELECT @rv = rand();

INSERT INTO dbo.R
(Number)
    values((@rv * 100));

SELECT * FROM R

    DROP VIEW IF EXISTS vwGetNewNumber;
    GO
    Create View vwGetNewNumber
    as
    Select CAST(RAND(CHECKSUM(NEWID())) * 62 as INT) + 1 as NextID,
    'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'as alpha_num;

    ---------------CTDE_GENERATE_PUBLIC_KEY -----------------
    DROP FUNCTION IF EXISTS CTDE_GENERATE_PUBLIC_KEY;  
    GO
    create function CTDE_GENERATE_PUBLIC_KEY()
    RETURNS NVARCHAR(32)
    AS 
    BEGIN
        DECLARE @private_key NVARCHAR(32);
        set @private_key = dbo.CTDE_GENERATE_32_BIT_KEY();
        return @private_key;
    END;
    go

---------------CTDE_GENERATE_32_BIT_KEY -----------------
DROP FUNCTION IF EXISTS CTDE_GENERATE_32_BIT_KEY;  
GO
CREATE function CTDE_GENERATE_32_BIT_KEY()
RETURNS NVARCHAR(32)
AS 
BEGIN
    DECLARE @public_key NVARCHAR(32);
    DECLARE @alpha_num NVARCHAR(62);
    DECLARE @start_index INT = 0;
    DECLARE @i INT = 0;
    select top 1 @alpha_num = alpha_num from vwGetNewNumber;
        WHILE @i < 32
        BEGIN
          select top 1 @start_index = NextID from vwGetNewNumber;
          set @public_key = concat (substring(@alpha_num,@start_index,1),@public_key);
          set @i = @i + 1;
        END;
    return @public_key;
END;
    select dbo.CTDE_GENERATE_PUBLIC_KEY() public_key;

my_table 세트 my_field = CEILING ((RAND (CAST (NEWID () AS varbinary)) * 10)) 업데이트

1에서 10 사이의 숫자입니다.

참고 URL : https://stackoverflow.com/questions/1045138/how-do-i-generate-random-number-for-each-row-in-a-tsql-select

반응형