Ho una sqlite
tabella con il seguente schema:
CREATE TABLE foo (bar VARCHAR)
Sto usando questa tabella come archivio per un elenco di stringhe.
Come seleziono una riga casuale da questa tabella?
Ho una sqlite
tabella con il seguente schema:
CREATE TABLE foo (bar VARCHAR)
Sto usando questa tabella come archivio per un elenco di stringhe.
Come seleziono una riga casuale da questa tabella?
Risposte:
Dai un'occhiata a Selezione di una riga casuale da una tabella SQLite
SELECT * FROM table ORDER BY RANDOM() LIMIT 1;
SELECT a.foo FROM a JOIN b ON a.id = b.id WHERE b.bar = 2 ORDER BY RANDOM() LIMIT 1;
ottengo sempre la stessa riga.
Le seguenti soluzioni sono molto più veloci di anktastic (il conteggio (*) costa molto, ma se puoi metterlo in cache, la differenza non dovrebbe essere così grande), che a sua volta è molto più veloce di "order by random ()" quando si dispone di un numero elevato di file, anche se presentano alcuni inconvenienti.
Se i tuoi rowid sono piuttosto compatti (cioè poche eliminazioni), puoi fare quanto segue (usando (select max(rowid) from foo)+1
invece di max(rowid)+1
fornisce prestazioni migliori, come spiegato nei commenti):
select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));
Se hai dei buchi, a volte proverai a selezionare un rowid inesistente e la selezione restituirà un set di risultati vuoto. Se ciò non è accettabile, puoi fornire un valore predefinito come questo:
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;
Questa seconda soluzione non è perfetta: la distribuzione di probabilità è più alta nell'ultima riga (quella con il rowid più alto), ma se aggiungi spesso cose alla tabella, diventerà un bersaglio mobile e la distribuzione delle probabilità dovrebbe essere molto meglio.
Ancora un'altra soluzione, se selezioni spesso elementi casuali da una tabella con molti buchi, potresti voler creare una tabella che contenga le righe della tabella originale ordinate in ordine casuale:
create table random_foo(foo_id);
Quindi, periodicamente, riempi nuovamente la tabella random_foo
delete from random_foo;
insert into random_foo select id from foo;
E per selezionare una riga casuale, puoi usare il mio primo metodo (non ci sono buchi qui). Ovviamente, quest'ultimo metodo presenta alcuni problemi di concorrenza, ma la ricostruzione di random_foo è un'operazione di manutenzione che non è probabile che accada molto spesso.
Tuttavia, ancora un altro modo, che ho trovato di recente su una mailing list , è di attivare un trigger su Elimina per spostare la riga con il rowid più grande nella riga eliminata corrente, in modo che non vengano lasciati buchi.
Infine, nota che il comportamento di rowid e un numero intero autoincremento della chiave primaria non è identico (con rowid, quando viene inserita una nuova riga, viene scelto max (rowid) +1, dove è il valore più alto mai visto + 1 per una chiave primaria), quindi l'ultima soluzione non funzionerà con un autoincrement in random_foo, ma gli altri metodi lo faranno.
SELECT max(rowid) + 1
sarà una query lenta - richiede una scansione completa della tabella. sqlite ottimizza solo la query SELECT max(rowid)
. Pertanto, questa risposta sarebbe migliorata da: select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));
Vedi questo per maggiori informazioni: sqlite.1065341.n5.nabble.com/…
È necessario inserire "order by RANDOM ()" nella query.
Esempio:
select * from quest order by RANDOM();
Vediamo un esempio completo
CREATE TABLE quest (
id INTEGER PRIMARY KEY AUTOINCREMENT,
quest TEXT NOT NULL,
resp_id INTEGER NOT NULL
);
Inserendo alcuni valori:
insert into quest(quest, resp_id) values ('1024/4',6), ('256/2',12), ('128/1',24);
Una selezione predefinita:
select * from quest;
| id | quest | resp_id |
1 1024/4 6
2 256/2 12
3 128/1 24
--
A selezionare casuale:
select * from quest order by RANDOM();
| id | quest | resp_id |
3 128/1 24
1 1024/4 6
2 256/2 12
--
* Ogni volta che si seleziona, l'ordine sarà diverso.
Se vuoi restituire solo una riga
select * from quest order by RANDOM() LIMIT 1;
| id | quest | resp_id |
2 256/2 12
--
* Ogni volta che selezioni, il reso sarà diverso.
Che dire:
SELECT COUNT(*) AS n FROM foo;
quindi scegli un numero casuale m in [0, n) e
SELECT * FROM foo LIMIT 1 OFFSET m;
Puoi anche salvare il primo numero ( n ) da qualche parte e aggiornarlo solo quando il conteggio del database cambia. In questo modo non devi eseguire il SELECT COUNT ogni volta.
OFFSET
sembra aumentare a seconda delle dimensioni dell'offset: la riga 2 è veloce, la riga 2 milioni richiede un po 'di tempo, anche quando tutti i dati in sono di dimensione fissa e dovrebbe essere in grado di cercarlo direttamente. Almeno, questo è quello che sembra in SQLite 3.7.13.
SELECT bar
FROM foo
ORDER BY Random()
LIMIT 1
Ecco una modifica della soluzione di @ ank:
SELECT *
FROM table
LIMIT 1
OFFSET ABS(RANDOM()) % MAX((SELECT COUNT(*) FROM table), 1)
Questa soluzione funziona anche per gli indici con spazi vuoti, perché randomizziamo un offset in un intervallo [0, count). MAX
viene utilizzato per gestire un caso con una tabella vuota.
Ecco i risultati dei test semplici su una tabella con 16k righe:
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
Ho trovato la seguente soluzione per i grandi database sqlite3 :
SELECT * FROM foo WHERE rowid = abs(random()) % (SELECT max(rowid) FROM foo) + 1;
La funzione abs (X) restituisce il valore assoluto dell'argomento numerico X.
La funzione random () restituisce un numero intero pseudo-casuale compreso tra -9223372036854775808 e +9223372036854775807.
L'operatore% restituisce il valore intero del suo operando sinistro modulo l'operando destro.
Infine, aggiungi +1 per evitare che rowid sia uguale a 0.