Ich muss Zeilen zufällig aus einer Oracle-Datenbank auswählen.
Beispiel: Nehmen Sie eine Tabelle mit 100 Zeilen an, wie ich 20 dieser Datensätze aus den gesamten 100 Zeilen zufällig zurückgeben kann.
Antworten:
SELECT *
FROM (
SELECT *
FROM table
ORDER BY DBMS_RANDOM.RANDOM)
WHERE rownum < 21;
SAMPLE () liefert nicht garantiert genau 20 Zeilen, ist jedoch möglicherweise geeignet (und bietet möglicherweise eine deutlich bessere Leistung als eine vollständige Abfrage + zufällige Sortierung für große Tabellen):
SELECT *
FROM table SAMPLE(20);
Hinweis: Das 20
hier ist ein ungefährer Prozentsatz, nicht die Anzahl der gewünschten Zeilen. In diesem Fall fordern Sie, da Sie 100 Zeilen haben, eine Stichprobe von 20% an, um ungefähr 20 Zeilen zu erhalten.
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;
Dies ist effizienter, da die Tabelle nicht sortiert werden muss.
Um zufällig 20 Zeilen auszuwählen, ist es meiner Meinung nach besser, die Menge nach dem Zufallsprinzip auszuwählen und die ersten 20 dieses Satzes auszuwählen.
Etwas wie:
Select *
from (select *
from table
order by dbms_random.value) -- you can also use DBMS_RANDOM.RANDOM
where rownum < 21;
Am besten für kleine Tabellen geeignet, um zu vermeiden, dass große Datenblöcke ausgewählt werden, nur um das meiste davon zu verwerfen.
Zusammenfassend wurden zwei Möglichkeiten eingeführt
1) using order by DBMS_RANDOM.VALUE clause
2) using sample([%]) function
Der erste Weg hat den Vorteil von 'RICHTIGKEIT', was bedeutet, dass Sie niemals ein Ergebnis erhalten, wenn es tatsächlich vorhanden ist, während Sie auf den zweiten Weg möglicherweise kein Ergebnis erhalten, obwohl Fälle vorliegen, die die Abfragebedingung erfüllen, da die Informationen während der Abtastung reduziert werden.
Der zweite Weg hat den Vorteil von 'EFFIZIENT', was bedeutet, dass Sie schneller Ergebnisse erzielen und Ihre Datenbank leicht belasten. Ich wurde vom DBA gewarnt, dass meine Abfrage auf die erste Weise die Datenbank lädt
Sie können je nach Interesse zwischen zwei Möglichkeiten wählen!
Bei großen Tabellen ist die Standardmethode mit Sortierung nach dbms_random.value nicht effektiv, da Sie die gesamte Tabelle scannen müssen und dbms_random.value eine ziemlich langsame Funktion ist und Kontextwechsel erfordert. Für solche Fälle gibt es 3 zusätzliche Methoden:
1: Verwenden sample
:
zum Beispiel:
select *
from s1 sample block(1)
order by dbms_random.value
fetch first 1 rows only
dh 1% aller Blöcke erhalten, dann zufällig sortieren und nur 1 Zeile zurückgeben.
2: Wenn Sie einen Index / Primärschlüssel für die Spalte mit normaler Verteilung haben , können Sie Min- und Max-Werte abrufen, Zufallswerte in diesem Bereich abrufen und die erste Zeile mit einem Wert abrufen, der größer oder gleich diesem zufällig generierten Wert ist.
Beispiel:
--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: Zufälligen Tabellenblock abrufen, Zeilen-ID generieren und Zeile mit dieser Zeilen-ID aus der Tabelle abrufen :
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
)
);
So wählen Sie aus jeder Gruppe eine Zufallsstichprobe aus:
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;
Ich bin mir nicht sicher, wie effizient es ist, aber wenn Sie viele Kategorien und Unterkategorien haben, scheint dies die Arbeit gut zu machen.
Tabelle
SELECT * FROM
(
SELECT column_name FROM table_name
ORDER BY dbms_random.value
)
WHERE rownum = 1;