IT박스

sqlite 테이블에서 임의의 행을 선택하십시오.

itboxs 2020. 8. 3. 08:39
반응형

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();

완전한 예를 보자

  1. 테이블을 작성하십시오.
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

반응형