Muszę losowo wybrać wiersze z bazy danych Oracle.
Przykład: Załóżmy, że tabela zawiera 100 wierszy, jak mogę losowo zwrócić 20 z tych rekordów z całych 100 wierszy.
SELECT *
FROM (
SELECT *
FROM table
ORDER BY DBMS_RANDOM.RANDOM)
WHERE rownum < 21;
SAMPLE () nie gwarantuje uzyskania dokładnie 20 wierszy, ale może być odpowiednie (i może działać znacznie lepiej niż pełne zapytanie + sortowanie losowe w przypadku dużych tabel):
SELECT * FROM table SAMPLE(20);
Uwaga:
20
tutaj jest przybliżona wartość procentowa, a nie liczba żądanych wierszy. W tym przypadku, ponieważ masz 100 wierszy, aby uzyskać około 20 wierszy, należy poprosić o próbkę 20%.źródło
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;
Jest to bardziej wydajne, ponieważ nie wymaga sortowania tabeli.
źródło
SELECT column FROM ( SELECT column, dbms_random.value FROM table ORDER BY 2 ) where rownum <= 20;
źródło
Aby losowo wybrać 20 rzędów, myślę, że lepiej byłoby wybrać wiele z nich w losowej kolejności i wybrać pierwsze 20 z tego zestawu.
Coś jak:
Select * from (select * from table order by dbms_random.value) -- you can also use DBMS_RANDOM.RANDOM where rownum < 21;
Najlepiej używać do małych tabel, aby uniknąć wybierania dużych fragmentów danych tylko w celu odrzucenia większości z nich.
źródło
Podsumowując, wprowadzono dwa sposoby
Pierwszy sposób ma przewagę w „PRAWIDŁOWOŚCI”, co oznacza, że nigdy nie uzyskasz wyniku, jeśli faktycznie istnieje, podczas gdy drugi sposób może nie uzyskać wyniku, nawet jeśli ma przypadki spełniające warunek zapytania, ponieważ informacje są zmniejszane podczas próbkowania.
Drugi sposób ma tę zaletę, że jest „WYDAJNY”, co oznacza, że szybciej uzyskasz wyniki i nie obciążysz bazy danych. Otrzymałem ostrzeżenie od DBA, że moje zapytanie przy użyciu pierwszego sposobu powoduje obciążenie bazy danych
Możesz wybrać jeden z dwóch sposobów w zależności od Twoich zainteresowań!
źródło
W przypadku dużych tabel standardowy sposób sortowania według dbms_random.value nie jest skuteczny, ponieważ trzeba przeskanować całą tabelę, a dbms_random.value jest funkcją dość powolną i wymaga przełączania kontekstu. W takich przypadkach istnieją 3 dodatkowe metody:
1:
sample
Klauzula użycia :na przykład:
select * from s1 sample block(1) order by dbms_random.value fetch first 1 rows only
tzn. pobierz 1% wszystkich bloków, a następnie posortuj je losowo i zwróć tylko 1 wiersz.
2: jeśli masz indeks / klucz podstawowy w kolumnie z rozkładem normalnym , możesz uzyskać wartości minimalne i maksymalne, uzyskać losową wartość z tego zakresu i otrzymać pierwszy wiersz z wartością większą lub równą tej losowo wygenerowanej wartości.
Przykład:
--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: pobierz losowy blok tabeli, wygeneruj identyfikator wiersza i pobierz wiersz z tabeli według tego identyfikatora wiersza :
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 ) );
źródło
Oto jak wybrać losową próbkę z każdej grupy:
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;
Nie jestem pewien, jak wydajne jest to, ale jeśli masz wiele kategorii i podkategorii, wydaje się, że działa to dobrze.
źródło
stół
Mamy stół nauczyciela
Składnia Oracle
SELECT * FROM ( SELECT column_name FROM table_name ORDER BY dbms_random.value ) WHERE rownum = 1;
Aby lepiej zrozumieć, wykonaj zrzut ekranu
źródło