Necesito seleccionar filas al azar de una base de datos de Oracle.
Ej .: Supongamos una tabla con 100 filas, cómo puedo devolver aleatoriamente 20 de esos registros de las 100 filas completas.
Respuestas:
SELECT *
FROM (
SELECT *
FROM table
ORDER BY DBMS_RANDOM.RANDOM)
WHERE rownum < 21;
No se garantiza que SAMPLE () le proporcione exactamente 20 filas, pero podría ser adecuado (y puede funcionar significativamente mejor que una consulta completa + clasificación aleatoria para tablas grandes):
SELECT *
FROM table SAMPLE(20);
Nota: 20
aquí es un porcentaje aproximado, no el número de filas deseadas. En este caso, dado que tiene 100 filas, para obtener aproximadamente 20 filas solicita una muestra del 20%.
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;
Esto es más eficiente ya que no necesita ordenar la tabla.
Para seleccionar 20 filas al azar, creo que sería mejor seleccionar todas las filas ordenadas al azar y seleccionar las primeras 20 de ese conjunto.
Algo como:
Select *
from (select *
from table
order by dbms_random.value) -- you can also use DBMS_RANDOM.RANDOM
where rownum < 21;
Se utiliza mejor para tablas pequeñas para evitar seleccionar grandes cantidades de datos solo para descartar la mayor parte de ellos.
En resumen, se introdujeron dos formas
1) using order by DBMS_RANDOM.VALUE clause
2) using sample([%]) function
La primera forma tiene la ventaja de 'CORRECCIÓN', lo que significa que nunca fallará en la obtención de resultados si realmente existe, mientras que en la segunda forma puede que no obtenga ningún resultado aunque tenga casos que satisfagan la condición de consulta, ya que la información se reduce durante el muestreo.
La segunda forma tiene la ventaja de "EFICIENTE", lo que significa que obtendrá resultados más rápido y le dará una carga ligera a su base de datos. Recibí una advertencia del DBA de que mi consulta usando la primera forma da cargas a la base de datos
¡Puede elegir una de dos formas según su interés!
En el caso de tablas grandes, la forma estándar de ordenar por dbms_random.value no es efectiva porque necesita escanear la tabla completa y dbms_random.value es una función bastante lenta y requiere cambios de contexto. Para tales casos, existen 3 métodos adicionales:
1: sample
cláusula de uso :
por ejemplo:
select *
from s1 sample block(1)
order by dbms_random.value
fetch first 1 rows only
es decir, obtenga el 1% de todos los bloques, luego ordénelos al azar y devuelva solo 1 fila.
2: si tiene un índice / clave principal en la columna con distribución normal , puede obtener valores mínimos y máximos, obtener un valor aleatorio en este rango y obtener la primera fila con un valor mayor o igual que ese valor generado aleatoriamente.
Ejemplo:
--big table with 1 mln rows with primary key on ID with normal distribution:
Create table s1(id primary key,padding) as
select level, rpad('x',100,'x')
from dual
connect by level<=1e6;
select *
from s1
where id>=(select
dbms_random.value(
(select min(id) from s1),
(select max(id) from s1)
)
from dual)
order by id
fetch first 1 rows only;
3: obtenga un bloque de tabla aleatorio, genere rowid y obtenga una fila de la tabla por este rowid :
select *
from s1
where rowid = (
select
DBMS_ROWID.ROWID_CREATE (
1,
objd,
file#,
block#,
1)
from
(
select/*+ rule */ file#,block#,objd
from v$bh b
where b.objd in (select o.data_object_id from user_objects o where object_name='S1' /* table_name */)
order by dbms_random.value
fetch first 1 rows only
)
);
A continuación, se explica cómo elegir una muestra aleatoria de cada grupo:
SELECT GROUPING_COLUMN,
MIN (COLUMN_NAME) KEEP (DENSE_RANK FIRST ORDER BY DBMS_RANDOM.VALUE)
AS RANDOM_SAMPLE
FROM TABLE_NAME
GROUP BY GROUPING_COLUMN
ORDER BY GROUPING_COLUMN;
No estoy seguro de cuán eficiente es, pero si tiene muchas categorías y subcategorías, esto parece funcionar bien.
mesa
SELECT * FROM
(
SELECT column_name FROM table_name
ORDER BY dbms_random.value
)
WHERE rownum = 1;