Wie wähle ich zufällig Zeilen in SQL aus?


226

Ich verwende MSSQL Server 2005. In meiner Datenbank habe ich eine Tabelle "customerNames", die zwei Spalten "Id" und "Name" enthält. 1.000 Ergebnisse.

Ich erstelle eine Funktionalität, bei der ich jedes Mal 5 Kunden zufällig auswählen muss. Kann mir jemand sagen, wie man eine Abfrage erstellt, die jedes Mal, wenn eine Abfrage ausgeführt wird, zufällige 5 Zeilen (ID und Name) erhält?


Zufällig ist keine häufige Anforderung für eine Datenbank. Ich war überrascht, einen Link für SQL
Paxic

2
Kommt darauf an, wie viel Zufälligkeit du willst. Siehe: msdn.microsoft.com/en-us/library/aa175776(SQL.80).aspx zum Vergleich von NEW_ID mit RAND ()
Shannon Severance

Antworten:


637
SELECT TOP 5 Id, Name FROM customerNames
ORDER BY NEWID()

Trotzdem scheint jeder auf diese Seite zu kommen, um eine allgemeinere Antwort auf Ihre Frage zu erhalten:

Auswählen einer zufälligen Zeile in SQL

Wählen Sie mit MySQL eine zufällige Zeile aus:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

Wählen Sie mit PostgreSQL eine zufällige Zeile aus:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Wählen Sie mit Microsoft SQL Server eine zufällige Zeile aus:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

Wählen Sie mit IBM DB2 eine zufällige Zeile aus

SELECT column, RAND() as IDX 
FROM table 
ORDER BY IDX FETCH FIRST 1 ROWS ONLY

Wählen Sie mit Oracle einen zufälligen Datensatz aus:

SELECT column FROM
( SELECT column FROM table
ORDER BY dbms_random.value )
WHERE rownum = 1

Wählen Sie eine zufällige Zeile mit SQLite:

SELECT column FROM table 
ORDER BY RANDOM() LIMIT 1

3
+1 für das direkte Posten der Antworten auf SO, anstatt auf eine externe Site (wie die akzeptierte Antwort) zu verlinken, die möglicherweise gesunken ist, wenn zukünftige Benutzer diese Frage betrachten.
Ray Zhou

17
Wird dies bei großen Tabellen sehr teuer, bei denen jede Zeile eine Zufallszahl erhält und dann ein großer nicht indizierter Zufallszahlensatz sortiert wird?
Andrey

Dies ist für die meisten Leute vielleicht offensichtlich, aber für mich war es nicht offensichtlich ... Die folgende Abfrage erhält nicht für jede Zeile einen neuen Zufallswert: update tbl_vouchers set tbl_UsersID = (select top(1) id from tbl_Users order by NEWID()) - Bearbeiten: Ich kann die Formatierung in Kommentaren nicht zum Laufen bringen :(
Mir

Du Genie! Ich hasse dich so sehr, weil ich das erst gesehen habe, als ich eine wahnsinnig lange Abfrage mit Unterabfragen und Zeilennummern geschrieben hatte.
Greenkode

5
Warnung: Bei großen Datenbanken weist diese Methode eine schlechte Leistung auf. Können Sie sich vorstellen, wie lange es dauern wird, einen zufälligen Wert für jede Zeile zu generieren, wenn die Datenbank über eine Million Einträge verfügt? Weitere Informationen und eine bessere Alternative finden Sie hier .
Francis Ngueukam


11

Falls jemand eine PostgreSQL-Lösung möchte:

select id, name
from customer
order by random()
limit 5;

Diese Antwort ist gut für PostgreSQL, sie benötigt kein Limit.
Aliasbody

9

Vielleicht hilft diese Seite weiter.

Für diejenigen, die nicht durchklicken möchten:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

2
sollte mindestens 1 durch 5 ersetzt haben :)
Roman m


5

Wenn Sie eine Tabelle mit Millionen von Zeilen haben und sich um die Leistung kümmern, könnte dies eine bessere Antwort sein:

SELECT * FROM Table1
WHERE (ABS(CAST(
  (BINARY_CHECKSUM
  (keycol1, NEWID())) as int))
  % 100) < 10

https://msdn.microsoft.com/en-us/library/cc441928.aspx


Beachten Sie, dass dadurch ungefähr 10% der Zeilen in der Tabelle ausgewählt werden. Wenn Sie eine genaue Anzahl von Zeilen oder mindestens N Zeilen auswählen müssen, funktioniert dieser Ansatz nicht.
LarsH

4

Dies ist eine alte Frage, aber der Versuch, ein neues Feld (entweder NEWID () oder ORDER BY rand ()) auf eine Tabelle mit einer großen Anzahl von Zeilen anzuwenden, wäre unerschwinglich teuer. Wenn Sie inkrementelle, eindeutige IDs haben (und keine Löcher haben), ist es effizienter, die X-Anzahl der auszuwählenden IDs zu berechnen, anstatt eine GUID oder ähnliches für jede einzelne Zeile anzuwenden und dann die oberste X-Nummer von zu übernehmen.

DECLARE @minValue int;
DECLARE @maxValue int;
SELECT @minValue = min(id), @maxValue = max(id) from [TABLE];

DECLARE @randomId1 int, @randomId2 int, @randomId3 int, @randomId4 int, @randomId5 int
SET @randomId1 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId2 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId3 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId4 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId5 = ((@maxValue + 1) - @minValue) * Rand() + @minValue

--select @maxValue as MaxValue, @minValue as MinValue
--  , @randomId1 as SelectedId1
--  , @randomId2 as SelectedId2
--  , @randomId3 as SelectedId3
--  , @randomId4 as SelectedId4
--  , @randomId5 as SelectedId5

select * from [TABLE] el
where el.id in (@randomId1, @randomId2, @randomId3, @randomId4, @randomId5)

Wenn Sie viel mehr Zeilen auswählen möchten, würde ich eine #tempTable mit einer ID und einer Reihe von rand () -Werten füllen und dann jeden rand () -Wert verwenden, um auf die min-max-Werte zu skalieren. Auf diese Weise müssen Sie nicht alle @ randomId1 ... n-Parameter definieren. Ich habe unten ein Beispiel mit einem CTE zum Auffüllen der Anfangstabelle eingefügt.

DECLARE @NumItems int = 100;

DECLARE @minValue int;
DECLARE @maxValue int;
SELECT @minValue = min(id), @maxValue = max(id) from [TABLE];
DECLARE @range int = @maxValue+1 - @minValue;

with cte (n) as (
   select 1 union all
   select n+1 from cte
   where n < @NumItems
)
select cast( @range * rand(cast(newid() as varbinary(100))) + @minValue as int) tp
into #Nt
from cte;

select * from #Nt ntt
inner join [TABLE] i on i.id = ntt.tp;

drop table #Nt;

@Protiguous, die von Ihnen vorgeschlagene Bearbeitung hat die zufällige Auswahl unterbrochen. Die Verwendung von min () und max (), die auf die Tabelle dbo.Tally64k angewendet werden, würde es dem Benutzer nicht ermöglichen, eine Zeile mit einer pk-ID> 65556 auszuwählen.
RIanGillis

Die Änderung des Tabellennamens war einfach ein Artefakt aus dem Test. Der tatsächliche Tabellenname spielt keine Rolle, solange die richtige Tabelle verwendet wird. min () und max () können beide in einer Abfrage anstatt in zwei abgefragt werden, was ich zeigen wollte.
Protiguous

@Protiguous Ah, ich sehe das jetzt, ich war verwirrt, weil du die 0-65k benutzt hast, als du das Min-Max gemacht hast, aber nicht später. Nach Ihrer letzten Bearbeitung wollte ich Sie tatsächlich nach den Auswirkungen der von Ihnen vorgenommenen Änderungen auf die Leistung fragen, da die Leistungsoptimierung eines meiner Interessen ist und scheinbar bedeutungslose Entscheidungen wie die Seite des Gleichheitszeichens, die Sie platzieren, tatsächlich erhebliche Auswirkungen haben können - - Würde das Gleiche für die 5 SET @ randomId ## -Aufrufe gelten? Oder ist das anders, weil es nicht aus einer tatsächlichen Tabelle ausgewählt wird?
RIanGillis

Ich bin mir nicht sicher, ob ich deine Frage verstehe. Fragen Sie sich, warum es 5 SET statt nur 1 SELECT @ id1 = rand (), @ id2 = rand () gibt? Dies liegt daran, dass mehrere Aufrufe einer rand () - Anweisung in 1 Anweisung dasselbe Ergebnis liefern, daher das getrennte SET. (rand () auf SQL Server ist eine deterministische Funktion, glaube ich.) Ich würde vermuten, dass 1 Auswahl gegen 5 Satz in Bezug auf die Leistung im Nanosekundenbereich liegt.
Protiguous

4
SELECT * FROM TABLENAME ORDER BY random() LIMIT 5; 

Alte Frage, aber diese Antwort lief bei Oracle nicht für mich.
Bär

SELECT * FROM (SELECT * FROM Tabelle ORDER BY DBMS_RANDOM.VALUE) WHERE rownum <number; @ Bär versuchen Sie dies
Narendra

3

Ich habe festgestellt, dass dies am besten für Big Data funktioniert.

SELECT TOP 1 Column_Name FROM dbo.Table TABLESAMPLE(1 PERCENT);

TABLESAMPLE(n ROWS) or TABLESAMPLE(n PERCENT) ist zufällig, muss aber hinzugefügt werden TOP n , um die richtige Stichprobengröße zu erhalten.

Bei NEWID()großen Tischen ist die Verwendung sehr langsam.


0

Wie in diesem Artikel erläutert , müssen Sie zum Mischen der SQL-Ergebnismenge einen datenbankspezifischen Funktionsaufruf verwenden.

Beachten Sie, dass sich das Sortieren einer großen Ergebnismenge mithilfe einer RANDOM-Funktion als sehr langsam herausstellen kann. Stellen Sie daher sicher, dass Sie dies bei kleinen Ergebnismengen tun.

Wenn Sie eine große Ergebnismenge mischen und anschließend einschränken müssen, ist es besser, etwas wie OracleSAMPLE(N) oder TABLESAMPLEin SQL Server oder PostgreSQL anstelle einer Zufallsfunktion in der ORDER BY-Klausel zu verwenden.

Angenommen, wir haben die folgende Datenbanktabelle:

Geben Sie hier die Bildbeschreibung ein

Und die folgenden Zeilen in der songTabelle:

| id | artist                          | title                              |
|----|---------------------------------|------------------------------------|
| 1  | Miyagi & Эндшпиль ft. Рем Дигга | I Got Love                         |
| 2  | HAIM                            | Don't Save Me (Cyril Hahn Remix)   |
| 3  | 2Pac ft. DMX                    | Rise Of A Champion (GalilHD Remix) |
| 4  | Ed Sheeran & Passenger          | No Diggity (Kygo Remix)            |
| 5  | JP Cooper ft. Mali-Koa          | All This Love                      |

Orakel

Unter Oracle müssen Sie die DBMS_RANDOM.VALUEFunktion verwenden, wie im folgenden Beispiel dargestellt:

SELECT
    artist||' - '||title AS song
FROM song
ORDER BY DBMS_RANDOM.VALUE

Wenn Sie die oben genannte SQL-Abfrage unter Oracle ausführen, erhalten Sie die folgende Ergebnismenge:

| song                                              |
|---------------------------------------------------|
| JP Cooper ft. Mali-Koa - All This Love            |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |

Beachten Sie, dass die Songs dank des DBMS_RANDOM.VALUEvon der ORDER BY-Klausel verwendeten Funktionsaufrufs in zufälliger Reihenfolge aufgelistet werden .

SQL Server

Unter SQL Server müssen Sie die NEWIDFunktion verwenden, wie im folgenden Beispiel dargestellt:

SELECT
    CONCAT(CONCAT(artist, ' - '), title) AS song
FROM song
ORDER BY NEWID()

Wenn Sie die oben genannte SQL-Abfrage unter SQL Server ausführen, erhalten Sie die folgende Ergebnismenge:

| song                                              |
|---------------------------------------------------|
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |
| JP Cooper ft. Mali-Koa - All This Love            |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |

Beachten Sie, dass die Songs dank des NEWIDvon der ORDER BY-Klausel verwendeten Funktionsaufrufs in zufälliger Reihenfolge aufgelistet werden .

PostgreSQL

Unter PostgreSQL müssen Sie die randomFunktion verwenden, wie im folgenden Beispiel dargestellt:

SELECT
    artist||' - '||title AS song
FROM song
ORDER BY random()

Wenn Sie die oben genannte SQL-Abfrage unter PostgreSQL ausführen, erhalten Sie die folgende Ergebnismenge:

| song                                              |
|---------------------------------------------------|
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| JP Cooper ft. Mali-Koa - All This Love            |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |

Beachten Sie, dass die Songs dank des randomvon der ORDER BY-Klausel verwendeten Funktionsaufrufs in zufälliger Reihenfolge aufgelistet werden .

MySQL

Unter MySQL müssen Sie die RANDFunktion verwenden, wie im folgenden Beispiel dargestellt:

SELECT
  CONCAT(CONCAT(artist, ' - '), title) AS song
FROM song
ORDER BY RAND()

Wenn Sie die oben genannte SQL-Abfrage unter MySQL ausführen, erhalten Sie die folgende Ergebnismenge:

| song                                              |
|---------------------------------------------------|
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| JP Cooper ft. Mali-Koa - All This Love            |

Beachten Sie, dass die Songs dank des RANDvon der ORDER BY-Klausel verwendeten Funktionsaufrufs in zufälliger Reihenfolge aufgelistet werden .


0

Wenn Sie eine große Tabelle verwenden und auf 10 Prozent der Daten zugreifen möchten, führen Sie den folgenden Befehl aus: SELECT TOP 10 PERCENT * FROM Table1 ORDER BY NEWID();

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.