Wie bekomme ich zufällig Datensätze aus der Oracle-Datenbank?


82

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:


111
SELECT *
FROM   (
    SELECT *
    FROM   table
    ORDER BY DBMS_RANDOM.RANDOM)
WHERE  rownum < 21;

1
Schlage mich dazu. Dadurch werden jedoch nur die ersten 20 Zeilen aus der Tabelle ausgewählt und nach dem Zufallsprinzip sortiert.
Nishant Sharma

10
Sie müssen sich bewusst sein, dass dies bei großen Tabellen eine sehr schwere Operation ist, da jeder Zeile zuerst eine Zufallszahl zugewiesen wird, dann nach diesem Wert sortiert wird und dann einige Datensätze daraus entnommen werden.
Roeland Van Heddegem

11
@NishantSharma, die Zeilen werden zufällig ausgewählt und dann begrenzt - Ihr Kommentar ist nicht korrekt.
Simon MᶜKenzie

6
Dieser Ansatz ist sehr langsam
Evan Kroske

1
@ JonBetts, ich denke, dass Probe viel schneller und ressourceneffizienter ist: stackoverflow.com/a/9920431/156787
Evan Kroske

50

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 20hier 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.


1
Die Stichprobe ist schnell, scheint aber nicht sehr zufällig zu sein. Datensätze am oberen / Anfang der Tabelle werden tendenziell bevorzugt.
craigrs84

1
Dies geschieht, wenn Sie die Abfrage stoppen, bevor sie die gesamte Tabelle durchläuft.
Jeffrey Kemp

2
Entschuldigung, ich habe einen Fehler gemacht, Ihr Beitrag ist in Ordnung und die Ergebnisse sind gleichmäßig verteilt. Wenn Sie "where rownum <= 20" in Kombination mit sample (20) hinzufügen, werden die Daten weniger zufällig.
craigrs84

14
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;

Dies ist effizienter, da die Tabelle nicht sortiert werden muss.


7
Das Stoppen der Stichprobe nach 20 Zeilen führt zu nicht zufälligen Ergebnissen (Zeilen, die früher in der Tabelle gefunden wurden, werden weitaus häufiger zurückgegeben als spätere). Es wird auch nicht garantiert, dass dies 20 Zeilen zurückgibt.
Jeffrey Kemp

10
SELECT column FROM
( SELECT column, dbms_random.value FROM table ORDER BY 2 )
where rownum <= 20;

4

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.


3

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!


1

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
      )
);

0

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.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.