2016-07-26 8 views
2

매번 10 개의 임의의 행을 테이블에서 가져와야하지만 쿼리를 반복해도 행이 반복되지 않습니다.SQL Server에서 임의의 데이터를 가져 오지만 반복되는 값은 없음

그러나 내가 모든 행을 얻으면 테이블에서 20 행을 가지며 처음에는 10 개의 임의 행을 얻습니다. 두 번째로는 10 개의 행을 남겨두고 3 번째 쿼리에서해야합니다. 무작위로 10 개의 행을 얻는다.

현재 내 무작위로 10 개 행을 얻기위한 쿼리

SELECT TOP 10 * 
FROM tablename 
ORDER BY NEWID() 

그러나 MSDN 좋은 성능이 쿼리

SELECT TOp 10 * FROM Table1 
    WHERE (ABS(CAST(
    (BINARY_CHECKSUM(*) * 
    RAND()) as int)) % 100) < 10 

을 제안한다. 그러나이 쿼리는 상수 행을 반환하지 않습니다. 이 질문에 뭔가를 제시해주십시오.

+0

보기 샘플 데이터하시기 바랍니다. – NEER

답변

2

두 번째 쿼리의 결과는 첫 번째 쿼리의 (임의의) 결과에 따라 달라 지므로 쿼리에 상태 비 저장을 사용할 수 없습니다. 어딘가에 상태 (이전 쿼리/쿼리에 대한 정보)를 저장해야합니다.

가장 간단한 해결 방법은 이미 검색 한 행 또는 해당 ID를 임시 테이블에 저장 한 다음 두 번째 쿼리에서 ... where id not in (select id from temp_table)을 쿼리하는 것입니다.

+0

데이터가 20000 행 이상인 것처럼 매우 큰 데이터입니다. 어떻게 임시 테이블에 데이터를 저장하고 몇 번이고 다시 실행할 수 있습니까? 성능이 좋지 않습니까? – Manikandan

+1

예를 들어, 임시 테이블에 레코드를 추가 할 때 성능이 떨어지 겠지만 결과를 원할 경우 유일한 옵션은 이미 선택된 행을 어딘가에 저장하는 것입니다. 인덱스가있는 테이블이 충분한 성능을 제공합니까? – Doliveras

+0

20k 행은 너무 많은 데이터가 아닙니다. 예 : 행에 정수 ID가 있고 사용 된 행의 ID 만 저장하면 임시 테이블이 메모리에 쉽게 캐싱되고 인덱스 없이도 빠르게 액세스 할 수있는 100kB에 들어갈 수 있습니다. –

0

Jiri Tousek이 말한 것처럼 실행하는 각 쿼리는 이전 쿼리가 반환 한 것을 알아야합니다.

테이블에 이전에 반환 된 행의 ID를 삽입 한 다음 새 결과가 해당 테이블에없는 것을 확인하는 대신 새 무작위 순서를 정의하는 임의의 숫자로 테이블에 열을 추가하기 만하면됩니다. 행 수

이 열을 임의의 숫자로 한 번 채우십시오.

이렇게하면 임의의 행 순서를 기억하고 안정적으로 만들 수 있으므로 쿼리 사이에 기억해야하는 것은 지금까지 요청한 임의 행 수입니다. 그런 다음 이전 쿼리에서 중지 한 곳부터 시작하여 필요한만큼의 행을 가져옵니다.


열을 RandomNumber binary(8) 테이블에 추가하십시오. 다른 크기를 선택할 수 있습니다. 8 바이트이면 충분합니다.

임의의 숫자로 채우십시오. 일단.

UPDATE tablename 
SET RandomNumber = CRYPT_GEN_RANDOM(8) 

RandomNumber 컬럼에 인덱스를 생성합니다. 고유 색인. 반복되는 난수 (20,000 개의 행과 8 개 길이의 난수가있을 법하지 않음)가 나온다면 모든 숫자가 고유 할 때까지 난수를 다시 생성하십시오 ( UPDATE 문을 다시 실행하십시오).

요청 처음 10 임의 행 :

SELECT TOP(10) * 
FROM tablename 
ORDER BY RandomNumber 

당신은/프로세스로 다음 10 개 임의 행이 마지막으로 사용 된 임의의 숫자를 기억하십시오. 이를 수행하는 가장 좋은 방법은이 10 개의 임의의 행을 처리하는 방법에 따라 다릅니다.

DECLARE @VarLastRandomNumber binary(8); 
SET @VarLastRandomNumber = ... 
-- the random number from the last row returned by the previous query 

요청 향후 10 임의 행 :

SELECT TOP(10) * 
FROM tablename 
WHERE RandomNumber > @VarLastRandomNumber 
ORDER BY RandomNumber 

프로세스를하고 마지막으로 사용 된 임의의 숫자를 기억한다.

반복. 보너스로 각 반복마다 다른 수의 임의의 행을 요청할 수 있습니다 (매번 10 번 일 필요는 없습니다). 내가 무엇을 할 것이라고

+1

을 추가 할 필요가있다. a) OP가 테이블 자체를 수정할 수 있다면 b) 테이블은이 프로세스에서 안정적이다. 새 행 또는 삭제 된 행), c) 한 번에 하나의 세션 만이 프로세스를 수행합니다. OP는 구체적인 세부 정보를 제공하지 않았기 때문에 우리는 실제로 알지 못합니다. –

0

은 각 시간, 한 번 기록 더미의 상단으로 이동합니다 선택한 것을 사용하는 경우 두 개의 새로운 필드 선택 (INT)와 TimesSelected (정수)를 너무

UPDATE tablename SET SELECTED = 0; 

WITH CTE AS (SELECT TOP 10 * 
FROM tablename 
ORDER BY TimesSelected ASC, NEWID()) 
UPDATE CTE SET SELECTED = 1, TimesSelected = TimesSelected + 1; 

SELECT * from tablename WHERE SELECTED = 1; 

을 가지고있다 , 그 아래의 레코드는 무작위로 선택됩니다.

당신이 커서 사용하기 위해 선택에 인덱스를 넣어

UPDATE tablename SET SELECTED = 0 WHERE SELECTED = 1; -- for performance 
+0

예. 레코드가 선택되고 1이되면 다른 모든 레코드가 1이 될 때까지 다시 선택할 수 없다고 생각합니다. 어떤 레코드는 2가되고 다른 레코드가 따라 올 때까지 부적격이됩니다. – Cato

0

가장 우아한 해결책, 당신은 일정 시간 내에서 연속 질의을 제공 할 것입니다 수행 할 수 있습니다 :

DECLARE rnd_cursor CURSOR FOR 
    SELECT col1, col2, ... 
    FROM tablename 
    ORDER BY NEWID(); 

OPEN rnd_cursor; 
FETCH NEXT FROM rnd_cursor; -- Repeat ten times 

커서를 열린 상태로 유지하고 필요에 따라 행을 계속 가져옵니다. 마지막 행을 가져온 후, 질문의 두 번째 부분으로

CLOSE rnd_cursor; 
DEALLOCATE rnd_cursor; 

을 새로운 커서를 엽니 다 : 작업을 완료 할 때 커서를 닫습니다

IF @@FETCH_STATUS <> 0 
BEGIN 
    CLOSE rnd_cursor; 
    OPEN rnd_cursor; 
END;