sqlite 테이블에서 임의의 행을 선택하십시오.
sqlite
다음 스키마 가있는 테이블이 있습니다.
CREATE TABLE foo (bar VARCHAR)
이 테이블을 문자열 목록의 저장소로 사용하고 있습니다.
이 테이블에서 임의의 행을 어떻게 선택합니까?
SQLite 테이블에서 임의의 행 선택을 살펴보십시오.
SELECT * FROM table ORDER BY RANDOM() LIMIT 1;
다음 솔루션은 anktastic (count (*) 비용이 많이 들지만 캐시 할 수 있다면 차이가 크지 않아야 함)보다 훨씬 빠릅니다. "random by random ()"보다 훨씬 빠릅니다. 행 수가 많을 때 불편하지만 행이 많은 경우
행 ID가 다소 압축되어 있으면 (즉, 삭제가 거의 없음) 다음을 수행 할 수 있습니다 ( 주석에 설명 된대로 성능을 향상시키는 (select max(rowid) from foo)+1
대신 사용 max(rowid)+1
).
select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));
구멍이있는 경우 때때로 존재하지 않는 rowid를 선택하려고하면 선택이 빈 결과 집합을 반환합니다. 이것이 허용되지 않으면 다음과 같은 기본값을 제공 할 수 있습니다.
select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1)) or rowid = (select max(rowid) from node) order by rowid limit 1;
이 두 번째 솔루션은 완벽하지 않습니다. 확률 분포는 마지막 행 (행 ID가 가장 높은 행)에서 높지만 종종 테이블에 물건을 추가하면 이동 목표가되고 확률 분포는 훨씬 낫다.
또 다른 해결책은 구멍이 많은 테이블에서 임의의 항목을 선택하는 경우 무작위로 정렬 된 원래 테이블의 행을 포함하는 테이블을 생성하는 것입니다.
create table random_foo(foo_id);
그런 다음 주기적으로 random_foo 테이블을 다시 채우십시오.
delete from random_foo;
insert into random_foo select id from foo;
그리고 임의의 행을 선택하기 위해 첫 번째 방법을 사용할 수 있습니다 (여기에 구멍이 없습니다). 물론이 마지막 방법에는 동시성 문제가 있지만 random_foo를 다시 작성하면 유지 관리 작업이 자주 발생하지 않습니다.
그러나 최근에 메일 링리스트 에서 찾은 또 다른 방법 은 delete에 트리거를 설정하여 가장 큰 rowid가있는 행을 현재 삭제 된 행으로 이동하여 구멍이 남지 않도록하는 것입니다.
마지막으로 rowid와 정수 기본 키 자동 증분의 동작은 동일하지 않습니다 (rowid의 경우 새 행이 삽입 될 때 max (rowid) +1이 선택됨). 기본 키)이므로 마지막 솔루션은 random_foo의 자동 증가와 함께 작동하지 않지만 다른 방법은 작동합니다.
이건 어떤가요:
SELECT COUNT(*) AS n FROM foo;
[0, n)에서 난수 m 을 선택 하고
SELECT * FROM foo LIMIT 1 OFFSET m;
첫 번째 숫자 ( n )를 어딘가에 저장 하고 데이터베이스 개수가 변경 될 때만 업데이트 할 수 있습니다. 이렇게하면 매번 SELECT COUNT를 수행 할 필요가 없습니다.
쿼리에 "order by RANDOM ()" 을 넣어야 합니다.
예:
select * from quest order by RANDOM();
완전한 예를 보자
- 테이블을 작성하십시오.
CREATE TABLE quest (
id INTEGER PRIMARY KEY AUTOINCREMENT,
quest TEXT NOT NULL,
resp_id INTEGER NOT NULL
);
일부 값 삽입
insert into quest(quest, resp_id) values ('1024/4',6), ('256/2',12), ('128/1',24);
기본 선택 :
select * from quest;
| id | quest | resp_id |
1 1024/4 6
2 256/2 12
3 128/1 24
--
무작위 선택 :
select * from quest order by RANDOM();
| id | quest | resp_id |
3 128/1 24
1 1024/4 6
2 256/2 12
--
* 선택할 때마다 순서가 다릅니다.
한 행만 반환하려면
select * from quest order by RANDOM() LIMIT 1;
| id | quest | resp_id |
2 256/2 12
--
* 선택할 때마다 반품이 달라집니다.
SELECT bar
FROM foo
ORDER BY Random()
LIMIT 1
@ank 솔루션의 수정 사항은 다음과 같습니다.
SELECT *
FROM table
LIMIT 1
OFFSET ABS(RANDOM()) % MAX((SELECT COUNT(*) FROM table), 1)
이 솔루션은 또한 범위가 [0, count] 인 오프셋을 랜덤 화하기 때문에 간격이있는 인덱스에도 적용됩니다. MAX
빈 테이블이있는 케이스를 처리하는 데 사용됩니다.
Here are simple test results on a table with 16k rows:
sqlite> .timer on
sqlite> select count(*) from payment;
16049
Run Time: real 0.000 user 0.000140 sys 0.000117
sqlite> select payment_id from payment limit 1 offset abs(random()) % (select count(*) from payment);
14746
Run Time: real 0.002 user 0.000899 sys 0.000132
sqlite> select payment_id from payment limit 1 offset abs(random()) % (select count(*) from payment);
12486
Run Time: real 0.001 user 0.000952 sys 0.000103
sqlite> select payment_id from payment order by random() limit 1;
3134
Run Time: real 0.015 user 0.014022 sys 0.000309
sqlite> select payment_id from payment order by random() limit 1;
9407
Run Time: real 0.018 user 0.013757 sys 0.000208
I came up with the following solution for the large sqlite3 databases:
SELECT * FROM foo WHERE rowid = abs(random()) % (SELECT max(rowid) FROM foo) + 1;
The abs(X) function returns the absolute value of the numeric argument X.
The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807.
The operator % outputs the integer value of its left operand modulo its right operand.
Finally, you add +1 to prevent rowid equal to 0.
참고URL : https://stackoverflow.com/questions/2279706/select-random-row-from-a-sqlite-table
'IT박스' 카테고리의 다른 글
Android에서 현재 위치를 얻는 방법 (0) | 2020.08.04 |
---|---|
디버그 정보를 사용하여 릴리스 빌드를 "full"또는 "pdb-only"로 컴파일해야합니까? (0) | 2020.08.04 |
Knockoutjs와 트위터 부트 스트랩 자동 완성 드롭 다운 / 콤보 박스 (0) | 2020.08.03 |
Intellij IDEA에서 텍스트를 새 줄로 바꾸려면 어떻게합니까? (0) | 2020.08.03 |
build.gradle에 maven 저장소 추가 (0) | 2020.08.03 |