SQL Server 테이블에서 임의의 레코드를 검색하는 간결한 방법이 있습니까?
내 단위 테스트 데이터를 무작위로 만들고 싶으므로 테이블에서 임의의 ID를 선택하는 간단한 방법을 찾고 있습니다. 영어의 경우 선택은 “ID가 테이블의 가장 낮은 ID와 테이블의 가장 높은 ID 사이의 임의의 숫자 인 테이블에서 하나의 ID를 선택하십시오.”입니다.
쿼리를 실행하고 null 값을 테스트 한 다음 null 인 경우 다시 실행하지 않고는 방법을 알아낼 수 없습니다.
아이디어?
답변
SQL Server 테이블에서 임의의 레코드를 검색하는 간결한 방법이 있습니까?
예
SELECT TOP 1 * FROM table ORDER BY NEWID()
설명
A NEWID()
는 각 행에 대해 생성되고 테이블은이를 기준으로 정렬됩니다. 첫 번째 레코드 (즉, GUID가 “가장 낮은”레코드)가 반환됩니다.
메모
-
GUID는 버전 4부터 의사 난수로 생성됩니다.
버전 4 UUID는 진정한 난수 또는 의사 난수에서 UUID를 생성하기위한 것입니다.
알고리즘은 다음과 같습니다.
- clock_seq_hi_and_reserved의 최상위 비트 2 개 (비트 6 및 7)를 각각 0과 1로 설정합니다.
- time_hi_and_version 필드의 최상위 4 비트 (비트 12 ~ 15)를 섹션 4.1.3의 4 비트 버전 번호로 설정합니다.
- 다른 모든 비트를 무작위로 (또는 의사 무작위로) 선택한 값으로 설정합니다.
— UUID (Universally Unique IDentifier) URN 네임 스페이스-RFC 4122
-
대안
SELECT TOP 1 * FROM table ORDER BY RAND()
은 생각대로 작동하지 않습니다.RAND()
쿼리 당 하나의 단일 값을 반환하므로 모든 행이 동일한 값을 공유합니다. -
GUID 값은 의사 난수이지만 더 까다로운 응용 프로그램에는 더 나은 PRNG가 필요합니다.
-
일반적인 성능은 약 1,000,000 행에 대해 10 초 미만이며 물론 시스템에 따라 다릅니다. 인덱스에 도달하는 것은 불가능하므로 성능이 상대적으로 제한됩니다.
답변
더 큰 테이블 TABLESAMPLE
에서는 전체 테이블을 스캔하지 않도록이를 위해 사용할 수도 있습니다 .
SELECT TOP 1 *
FROM YourTable
TABLESAMPLE (1000 ROWS)
ORDER BY NEWID()
는 ORDER BY NEWID
여전히 데이터 페이지에서 먼저 표시 만 반환 행을 방지하기 위해 필요합니다.
사용할 수는 테이블의 크기와 정의에 따라 신중하게 선택해야하며 행이 반환되지 않으면 재시도 논리를 고려할 수 있습니다. 이 기술의 배후에있는 수학 및 기술이 작은 테이블에 적합하지 않은 이유가 여기에서 설명됩니다.
답변
또한 MIN (Id)과 MAX (Id) 사이의 임의의 ID를 얻는 방법을 시도한 다음
SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid
항상 한 행을 얻습니다.
답변
대용량 데이터를 선택하려는 경우 내가 아는 가장 좋은 방법은 다음과 같습니다.
SELECT * FROM Table1
WHERE (ABS(CAST(
(BINARY_CHECKSUM
(keycol1, NEWID())) as int))
% 100) < 10
출처 : MSDN
답변
나는 내가 시도한 방법을 개선하기 위해이 게시물을 보았습니다. 나는 그것이 오래되었다는 것을 알고 있지만이 방법은 나열되지 않았습니다. 테스트 데이터를 만들고 적용하고 있습니다. 이것은 @st (두 문자 상태)로 호출 된 SP에서 “주소”에 대한 방법을 보여줍니다.
Create Table ##TmpAddress (id Int Identity(1,1), street VarChar(50), city VarChar(50), st VarChar(2), zip VarChar(5))
Insert Into ##TmpAddress(street, city, st, zip)
Select street, city, st, zip
From tbl_Address (NOLOCK)
Where st = @st
-- unseeded RAND() will return the same number when called in rapid succession so
-- here, I seed it with a guaranteed different number each time. @@ROWCOUNT is the count from the most recent table operation.
Set @csr = Ceiling(RAND(convert(varbinary, newid())) * @@ROWCOUNT)
Select street, city, st, Right(('00000' + ltrim(zip)),5) As zip
From ##tmpAddress (NOLOCK)
Where id = @csr
답변
개별 행의 무작위 샘플을 정말로 원한다면 TABLESAMPLE을 사용하는 대신 행을 무작위로 필터링하도록 쿼리를 수정하십시오. 예를 들어 다음 쿼리는 NEWID 함수를 사용하여 Sales.SalesOrderDetail 테이블 행의 약 1 %를 반환합니다.
SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
SalesOrderID 열은 CHECKSUM 식에 포함되므로 NEWID ()는 행당 한 번씩 평가하여 행 단위로 샘플링을 수행합니다. 표현식 CAST (CHECKSUM (NEWID (), SalesOrderID) & 0x7fffffff AS float / CAST (0x7fffffff AS int)는 0과 1 사이의 임의의 float 값으로 평가됩니다. “
출처 : http://technet.microsoft.com/en-us/library/ms189108(v=sql.105).aspx
이에 대해서는 아래에서 자세히 설명합니다.
어떻게 작동합니까? WHERE 절을 분리하여 설명해 봅시다.
CHECKSUM 함수는 목록의 항목에 대한 체크섬을 계산합니다. NEWID ()는 새로운 임의의 GUID를 반환하는 함수이므로 SalesOrderID가 필요한지 여부는 논쟁의 여지가 있습니다. 따라서 임의의 숫자에 상수를 곱하면 어떤 경우에도 임의의 값이 생성됩니다. 실제로 SalesOrderID를 제외해도 아무런 차이가없는 것 같습니다. 당신이 예리한 통계 학자이고 이것의 포함을 정당화 할 수 있다면, 아래 코멘트 섹션을 사용하고 왜 내가 틀렸는 지 알려주세요!
CHECKSUM 함수는 VARBINARY를 반환합니다. 바이너리에서 (111111111 …)에 해당하는 0x7fffffff로 비트 AND 연산을 수행하면 사실상 0과 1의 임의 문자열을 나타내는 10 진수 값이 생성됩니다. 계수 0x7fffffff로 나누면이 10 진수 숫자를 0과 1 사이의 숫자로 효과적으로 정규화합니다. 그런 다음 각 행이 최종 결과 집합에 포함될 수 있는지 여부를 결정하기 위해 임계 값 1 / x (이 경우 0.01)가 사용됩니다. x는 샘플로 검색 할 데이터의 백분율입니다.