Tengo una sqlite
tabla con el siguiente esquema:
CREATE TABLE foo (bar VARCHAR)
Estoy usando esta tabla como almacenamiento para una lista de cadenas.
¿Cómo selecciono una fila aleatoria de esta tabla?
Tengo una sqlite
tabla con el siguiente esquema:
CREATE TABLE foo (bar VARCHAR)
Estoy usando esta tabla como almacenamiento para una lista de cadenas.
¿Cómo selecciono una fila aleatoria de esta tabla?
Respuestas:
Eche un vistazo a Seleccionar una fila aleatoria de una tabla 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;
, siempre obtengo la misma fila.
Las siguientes soluciones son mucho más rápidas que las de anktastic (el recuento (*) cuesta mucho, pero si puede almacenarlo en caché, la diferencia no debería ser tan grande), que en sí mismo es mucho más rápido que el "orden aleatorio ()" cuando tienes una gran cantidad de filas, aunque tienen algunos inconvenientes.
Si sus rowids están bastante empaquetados (es decir, pocas eliminaciones), puede hacer lo siguiente (usar en (select max(rowid) from foo)+1
lugar de max(rowid)+1
ofrece un mejor rendimiento, como se explica en los comentarios):
select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));
Si tiene huecos, a veces intentará seleccionar un ID de fila inexistente y la selección devolverá un conjunto de resultados vacío. Si esto no es aceptable, puede proporcionar un valor predeterminado como este:
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;
Esta segunda solución no es perfecta: la distribución de probabilidad es más alta en la última fila (la que tiene el ID de fila más alto), pero si a menudo agrega cosas a la tabla, se convertirá en un objetivo móvil y la distribución de probabilidades debería ser mucho mejor.
Otra solución más, si a menudo selecciona elementos aleatorios de una tabla con muchos huecos, es posible que desee crear una tabla que contenga las filas de la tabla original ordenadas en orden aleatorio:
create table random_foo(foo_id);
Luego, periódicamente, vuelva a llenar la tabla random_foo
delete from random_foo;
insert into random_foo select id from foo;
Y para seleccionar una fila aleatoria, puede usar mi primer método (aquí no hay agujeros). Por supuesto, este último método tiene algunos problemas de concurrencia, pero la reconstrucción de random_foo es una operación de mantenimiento que no es probable que suceda con mucha frecuencia.
Sin embargo, otra forma más, que encontré recientemente en una lista de correo , es poner un disparador en eliminar para mover la fila con el ID de fila más grande a la fila eliminada actual, de modo que no queden huecos.
Por último, tenga en cuenta que el comportamiento de rowid y un autoincrement de clave primaria entera no es idéntico (con rowid, cuando se inserta una nueva fila, se elige max (rowid) +1, donde es higest-value-ever-seen + 1 para una clave primaria), por lo que la última solución no funcionará con un autoincremento en random_foo, pero los otros métodos sí.
SELECT max(rowid) + 1
será una consulta lenta; requiere un escaneo completo de la tabla. sqlite solo optimiza la consulta SELECT max(rowid)
. Por lo tanto, esta respuesta se mejoraría: select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));
Vea esto para obtener más información: sqlite.1065341.n5.nabble.com/…
Necesita poner "orden por RANDOM ()" en su consulta.
Ejemplo:
select * from quest order by RANDOM();
Veamos un ejemplo completo
CREATE TABLE quest (
id INTEGER PRIMARY KEY AUTOINCREMENT,
quest TEXT NOT NULL,
resp_id INTEGER NOT NULL
);
Insertando algunos valores:
insert into quest(quest, resp_id) values ('1024/4',6), ('256/2',12), ('128/1',24);
Una selección predeterminada:
select * from quest;
| id | quest | resp_id |
1 1024/4 6
2 256/2 12
3 128/1 24
--
Un selecto aleatorio:
select * from quest order by RANDOM();
| id | quest | resp_id |
3 128/1 24
1 1024/4 6
2 256/2 12
--
* Cada vez que seleccione, el orden será diferente.
Si desea devolver solo una fila
select * from quest order by RANDOM() LIMIT 1;
| id | quest | resp_id |
2 256/2 12
--
* Cada vez que selecciones, la devolución será diferente.
Qué pasa:
SELECT COUNT(*) AS n FROM foo;
luego elija un número aleatorio m en [0, n) y
SELECT * FROM foo LIMIT 1 OFFSET m;
Incluso puede guardar el primer número ( n ) en algún lugar y actualizarlo solo cuando cambie el recuento de la base de datos. De esa manera, no tendrá que hacer SELECT COUNT cada vez.
OFFSET
parece aumentar según el tamaño del desplazamiento: la fila 2 es rápida, la fila 2 millones lleva un tiempo, incluso cuando todos los datos en el son de tamaño fijo y debería poder buscarlo directamente. Al menos, eso es lo que parece en SQLite 3.7.13.
SELECT bar
FROM foo
ORDER BY Random()
LIMIT 1
Aquí hay una modificación de la solución de @ ank:
SELECT *
FROM table
LIMIT 1
OFFSET ABS(RANDOM()) % MAX((SELECT COUNT(*) FROM table), 1)
Esta solución también funciona para índices con espacios, porque aleatorizamos un desplazamiento en un rango [0, cuenta). MAX
se utiliza para manejar un caso con mesa vacía.
Aquí hay resultados de pruebas simples en una tabla con 16k filas:
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
Se me ocurrió la siguiente solución para las grandes bases de datos sqlite3 :
SELECT * FROM foo WHERE rowid = abs(random()) % (SELECT max(rowid) FROM foo) + 1;
La función abs (X) devuelve el valor absoluto del argumento numérico X.
La función random () devuelve un entero pseudoaleatorio entre -9223372036854775808 y +9223372036854775807.
El operador% genera el valor entero de su operando izquierdo módulo su operando derecho.
Finalmente, agrega +1 para evitar que rowid sea igual a 0.