Jak zażądać losowego wiersza w SQL?

510

Jak mogę zażądać losowego wiersza (lub tak zbliżonego do naprawdę losowego, jak to możliwe) w czystym SQL?

sverrejoh
źródło
Zawsze robiłem to w php po wynikach zapytania z sql ... jest to prawdopodobnie znacznie szybsze w przetwarzaniu zgodnie z dodatkiem 1 do rozwiązania
CheeseConQueso
2
Wydaje się, że nie ma rozwiązania „czystego SQL”, które działałoby na każdym dbms ... istnieje rozwiązanie dla każdego z nich.
Manu,
Wersja wydajności: stackoverflow.com/questions/4329396/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

735

Zobacz ten post: SQL, aby wybrać losowy wiersz z tabeli bazy danych . Omówiono metody wykonywania tego w MySQL, PostgreSQL, Microsoft SQL Server, IBM DB2 i Oracle (z tego łącza kopiowane są następujące elementy):

Wybierz losowy wiersz za pomocą MySQL:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

Wybierz losowy wiersz za pomocą PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Wybierz losowy wiersz za pomocą Microsoft SQL Server:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

Wybierz losowy wiersz za pomocą IBM DB2

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

Wybierz losowy rekord z Oracle:

SELECT column FROM
( SELECT column FROM table
ORDER BY dbms_random.value )
WHERE rownum = 1
Yaakov Ellis
źródło
30
-1 za poleganie na order by rand()lub równoważne we wszystkich dbs: | wspomniano również tutaj .
AD7six
20
Dziesięć lat temu jakiś facet powiedział, że używanie ORDER BY RAND()jest złe ...
trejder
ORDER BY NEWID () wydaje się być znacznie wolniejszy na SQL Server. Moje zapytanie wygląda następująco: wybierz najlepsze 1000 C.CustomerId, CL.LoginName z połączenia wewnętrznego klienta C LinkedAccount LA na C.CustomerId = LA.CustomerId wewnętrzne dołączenie CustomerLogin CL na C.CustomerId = CL.CustomerId grupy przez C.CustomerId, CL. LoginName o liczbie (*)> 1 zamówienie według NEWID () Usunięcie wiersza „zamówienie według NEWID ()” powoduje zwrócenie wyników znacznie szybciej.
Ben Power
3
Do SQLite użyj funkcji RANDOM ().
Slam
10
Te rozwiązania nie są skalowane. Są O(n)z nliczbą rekordów w tabeli. Wyobraź sobie, że masz milion rekordów, czy naprawdę chcesz wygenerować milion losowych liczb lub unikatowych identyfikatorów? Wolałbym użyć COUNT()i włączyć to w nowym LIMITwyrażeniu z pojedynczą liczbą losową.
Christian Hujer
174

Rozwiązania takie jak Jeremies:

SELECT * FROM table ORDER BY RAND() LIMIT 1

działają, ale potrzebują sekwencyjnego skanowania całej tabeli (ponieważ należy obliczyć losową wartość związaną z każdym wierszem - aby można było ustalić najmniejszą), co może być dość powolne w przypadku tabel nawet średnich. Moja rekomendacja to użycie indeksowanej kolumny numerycznej (wiele tabel ma je jako klucze podstawowe), a następnie napisanie czegoś takiego:

SELECT * FROM table WHERE num_value >= RAND() * 
    ( SELECT MAX (num_value ) FROM table ) 
ORDER BY num_value LIMIT 1

Działa to w czasie logarytmicznym, niezależnie od wielkości tabeli, jeśli num_valuejest indeksowane. Jedno zastrzeżenie: zakłada się, że num_valuejest on równomiernie rozłożony w zakresie 0..MAX(num_value). Jeśli zestaw danych silnie odbiega od tego założenia, otrzymasz wypaczone wyniki (niektóre wiersze pojawią się częściej niż inne).

Szara Pantera
źródło
8
Druga sugestia nie jest przypadkowa. Nie możesz przewidzieć, który rząd zostanie wybrany, ale gdybyś musiał postawić, postawiłbyś na drugi rząd. I nigdy nie postawiłbyś na ostatni rząd, jest mniej prawdopodobne, że zostaniesz wybrany bez względu na rozkład wartości_wartości i jak duży jest twój stół.
Etienne Racine
1
Wiem, że zwykle funkcje RAND () nie są bardzo wysokiej jakości, ale poza tym możesz wyjaśnić, dlaczego wybór nie byłby przypadkowy?
Gray Panther
13
Pierwszy jest NIEPRAWIDŁOWY w SQL Server. Funkcja RAND () jest wywoływana tylko raz na zapytanie, a nie raz na wiersz. Więc zawsze wybiera pierwszy wiersz (spróbuj).
Jeff Walker Code Ranger
3
Drugi zakłada również, że wszystkie wiersze są rozliczone: możliwe jest, że wybierze wiersz, który został usunięty.
Sam Rueby,
3
@ Sam.Rueby W rzeczywistości liczba_wartości> = RAND () ... limit 1 zapewnia, że ​​puste wiersze będą pomijane, dopóki nie znajdzie się wiersz opuszczający.
ghord
62

Nie wiem, jak to jest wydajne, ale używałem go wcześniej:

SELECT TOP 1 * FROM MyTable ORDER BY newid()

Ponieważ identyfikatory GUID są dość losowe, kolejność oznacza, że ​​otrzymujesz losowy wiersz.

Matt Hamilton
źródło
1
Korzystam z serwera MS SQL, WYBIERZ TOP 1 * FROM some_table_name ORDER BY NEWID () działał dla mnie świetnie, dzięki za porady chłopaki!
To dokładnie to samo, coORDER BY RAND() LIMIT 1
Ken Bloom
6
Jest to również bardzo specyficzne dla bazy danych, ponieważ używa TOP 1i newid().
Gray
12
To jest zły pomysł. Ta metoda nie używa indeksu, chyba że każda kolumna jest indeksowana indywidualnie. Tabela z 100 milionami rekordów może zająć bardzo dużo czasu, aby uzyskać jeden rekord.
Switch
1
@ Przełącz i jakie rozwiązanie byś zaproponował?
Akmal Salikhov,
31
ORDER BY NEWID()

trwa 7.4 milliseconds

WHERE num_value >= RAND() * (SELECT MAX(num_value) FROM table)

bierze 0.0065 milliseconds!

Zdecydowanie wybiorę tę drugą metodę.

Neel
źródło
2
Druga opcja nie wybiera ostatniego rzędu. Nie wiem dlaczego - po prostu to zaznaczam.
Voldemort
7
@Voldemort: rand()zwraca liczbę zmiennoprzecinkową ngdzie 0 < n < 1. Zakładając, że num_valuejest liczbą całkowitą, zwracana wartość rand() * max(num_value)zostanie również wymuszona na liczbę całkowitą, co spowoduje obcięcie wszystkiego po przecinku. Stąd rand() * max(num_value)będzie zawsze być mniejsza niż max(num_value), dlatego nigdy nie zostanie wybrany ostatni wiersz.
Ian Kemp
Nie będę efektywny, jeśli moje dane będą często usuwane - jeśli znajdę lukę, będę musiał ponownie uruchomić całe zapytanie.
Loic Coenen
1
@IanKemp Głupie pytanie, więc dlaczego po prostu nie użyć SELECT MAX (wartość_wartości) + 1 ?? Ponieważ rand (lub w większości przypadków RANDOM) zwraca [0,1), otrzymasz pełny zakres wartości. Poza tym tak, masz rację, musisz naprawić zapytanie.
tekHedd,
13

Nie powiedziałeś, którego serwera używasz. W starszych wersjach SQL Server możesz użyć tego:

select top 1 * from mytable order by newid()

W SQL Server 2005 i nowszych można użyć TABLESAMPLElosowej próbki, która jest powtarzalna:

SELECT FirstName, LastName
FROM Contact 
TABLESAMPLE (1 ROWS) ;
Jon Galloway
źródło
9
MSDN twierdzi, że newid () jest preferowany w stosunku do tabel przykładowych dla naprawdę losowych wyników: msdn.microsoft.com/en-us/library/ms189108.aspx
Andrew Hedges
7
@Andrew Hedges: ZAMÓWIENIE BY NEWID () jest zbyt kosztowne
Andrei Rînea
10

Dla SQL Server

Funkcja newid () / order by będzie działać, ale będzie bardzo kosztowna dla dużych zestawów wyników, ponieważ musi wygenerować identyfikator dla każdego wiersza, a następnie je posortować.

TABLESAMPLE () jest dobry z punktu widzenia wydajności, ale dostaniesz zbijanie wyników (wszystkie wiersze na stronie zostaną zwrócone).

Aby uzyskać lepszą skuteczność prawdziwej próbki losowej, najlepszym sposobem jest losowe odfiltrowanie wierszy. Znalazłem następujący przykładowy kod w artykule SQL Server Books Online Ograniczanie zestawów wyników za pomocą TABLESAMPLE :

Jeśli naprawdę chcesz losowej próbki pojedynczych wierszy, zmodyfikuj zapytanie, aby odfiltrować wiersze losowo, zamiast używać TABLESAMPLE. Na przykład w poniższym zapytaniu użyto funkcji NEWID do zwrócenia około jednego procenta wierszy tabeli Sales.SalesOrderDetail:

SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(),SalesOrderID) & 0x7fffffff AS float)
              / CAST (0x7fffffff AS int)

Kolumna SalesOrderID jest zawarta w wyrażeniu CHECKSUM, dzięki czemu NEWID () ocenia raz na wiersz, aby uzyskać próbkowanie na podstawie wiersza. Wyrażenie CAST (CHECKSUM (NEWID (), SalesOrderID) i 0x7fffffff AS float / CAST (0x7fffffff AS int) zwraca losową wartość od 0 do 1.

Po uruchomieniu z tabelą zawierającą 1 000 000 wierszy, oto moje wyniki:

SET STATISTICS TIME ON
SET STATISTICS IO ON

/* newid()
   rows returned: 10000
   logical reads: 3359
   CPU time: 3312 ms
   elapsed time = 3359 ms
*/
SELECT TOP 1 PERCENT Number
FROM Numbers
ORDER BY newid()

/* TABLESAMPLE
   rows returned: 9269 (varies)
   logical reads: 32
   CPU time: 0 ms
   elapsed time: 5 ms
*/
SELECT Number
FROM Numbers
TABLESAMPLE (1 PERCENT)

/* Filter
   rows returned: 9994 (varies)
   logical reads: 3359
   CPU time: 641 ms
   elapsed time: 627 ms
*/    
SELECT Number
FROM Numbers
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), Number) & 0x7fffffff AS float) 
              / CAST (0x7fffffff AS int)

SET STATISTICS IO OFF
SET STATISTICS TIME OFF

Jeśli możesz uciec od używania TABLESAMPLE, zapewni to najlepszą wydajność. W przeciwnym razie użyj metody newid () / filter. newid () / order by powinno być ostatecznością, jeśli masz duży zestaw wyników.

Rob Boek
źródło
4

Jeśli to możliwe, użyj przechowywanych instrukcji, aby uniknąć nieskuteczności obu indeksów w RND () i tworząc pole numeru rekordu.

PREPARE RandomRecord FROM „SELECT * FROM table LIMIT?, 1”;
SET @ n = FLOOR (RAND () * (SELECT COUNT (*) FROM table));
WYKONAJ RandomRecord USING @n;
ldrut
źródło
To rozwiązanie zajmuje się także zwracaniem losowych wierszy, gdy indeksowana wartość liczbowa stosowana w powyższej klauzuli where nie jest równo rozłożona; więc nawet jeśli zajmuje to prawie taki sam (stały) czas, jak użycie gdzie id_value> = RAND () * MAX (id_value), to lepiej.
guido
O ile wiem, nie działa to w stałym czasie, działa w czasie liniowym. W najgorszym przypadku @n jest równy liczbie wierszy w tabeli, a „WYBIERZ * Z LIMITU tabeli? 1” ocenia @n - 1 wierszy, aż dojdzie do ostatniego.
Andres Riofrio,
3

Najlepszym sposobem jest umieszczenie losowej wartości w nowej kolumnie tylko w tym celu i użycie czegoś takiego (kod pseude + SQL):

randomNo = random()
execSql("SELECT TOP 1 * FROM MyTable WHERE MyTable.Randomness > $randomNo")

Jest to rozwiązanie zastosowane w kodzie MediaWiki. Oczywiście istnieje pewne odchylenie w stosunku do mniejszych wartości, ale stwierdzono, że wystarczyło zawinąć losową wartość do zera, gdy nie zostaną pobrane żadne wiersze.

Rozwiązanie newid () może wymagać pełnego skanowania tabeli, aby do każdego wiersza można było przypisać nowy identyfikator GUID, który będzie znacznie mniej wydajny.

rozwiązanie rand () może w ogóle nie działać (tj. z MSSQL), ponieważ funkcja zostanie oceniona tylko raz, a do każdego wiersza zostanie przypisany ten sam „losowy” numer.

Ishmaeel
źródło
1
Zawijanie, gdy otrzymasz 0 wyników, zapewnia próbkę o możliwej do udowodnienia losowości (nie tylko „wystarczająco dobrą”). To rozwiązanie prawie skaluje się do zapytań wielowierszowych (pomyśl „przetasowanie partii”). Problem polega na tym, że wyniki są często wybierane w tych samych grupach. Aby obejść ten problem, musisz ponownie rozdzielić losowe liczby, których właśnie użyłeś. Możesz oszukiwać, śledząc randomNo i ustawiając go na maksimum (losowość) z wyników, ale następnie p (wiersz i w zapytaniu 1 ORAZ wiersz i w zapytaniu 2) == 0, co jest niesprawiedliwe. Pozwól mi zrobić matematykę, a wrócę do ciebie z naprawdę uczciwym planem.
alsuren
3

W przypadku SQL Server 2005 i 2008, jeśli chcemy losową próbkę pojedynczych wierszy (z Books Online ):

SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
Santiago Cepas
źródło
3

Natychmiastowe użycie RAND (), ponieważ nie jest to zalecane , możesz po prostu uzyskać max ID (= Max):

SELECT MAX(ID) FROM TABLE;

uzyskaj losowość między 1..Max (= My_Generated_Random)

My_Generated_Random = rand_in_your_programming_lang_function(1..Max);

a następnie uruchom ten SQL:

SELECT ID FROM TABLE WHERE ID >= My_Generated_Random ORDER BY ID LIMIT 1

Zauważ, że sprawdzi, czy wszystkie wiersze są identyczne lub WYŻSZE niż wybrana wartość. Możliwe jest również wyszukanie wiersza w dół tabeli i uzyskanie identycznego lub niższego identyfikatora niż My_Generated_Random, a następnie zmodyfikowanie zapytania w następujący sposób:

SELECT ID FROM TABLE WHERE ID <= My_Generated_Random ORDER BY ID DESC LIMIT 1
forsberg
źródło
Co by się stało, gdyby wygenerowany losowy identyfikator nie istniał już w tabeli? Usunięte lub pasywne wiersze, których nie chcesz pokazywać użytkownikowi, spowodowałyby problemy.
Ebleme
Nic. Otrzymasz NAJBLIŻSZY, nie dokładny numer identyfikacyjny. Jeśli uważasz, że id = 1 należy usunąć, wymień 1 na minimum.
forsberg,
2

Jak wskazano w komentarzu @ BillKarwin do odpowiedzi @ cnu ...

Kiedy kombinuję z LIMITEM, odkryłem, że działa znacznie lepiej (przynajmniej w PostgreSQL 9.1) do ŁĄCZENIA z losowym porządkowaniem, a nie bezpośrednio porządkować rzeczywiste wiersze: np.

SELECT * FROM tbl_post AS t
JOIN ...
JOIN ( SELECT id, CAST(-2147483648 * RANDOM() AS integer) AS rand
       FROM tbl_post
       WHERE create_time >= 1349928000
     ) r ON r.id = t.id
WHERE create_time >= 1349928000 AND ...
ORDER BY r.rand
LIMIT 100

Upewnij się tylko, że „r” generuje wartość „rand” dla każdej możliwej wartości klucza w złożonym zapytaniu, które jest z nią połączone, ale nadal ogranicza liczbę wierszy „r”, jeśli to możliwe.

CAST as Integer jest szczególnie pomocny dla PostgreSQL 9.2, który ma specyficzną optymalizację sortowania dla liczb całkowitych i zmiennoprzecinkowych o pojedynczej precyzji.

karmakaze
źródło
1

Większość rozwiązań tutaj ma na celu uniknięcie sortowania, ale nadal muszą wykonać sekwencyjne skanowanie tabeli.

Istnieje również sposób na uniknięcie skanowania sekwencyjnego poprzez przełączenie na skanowanie indeksu. Jeśli znasz wartość indeksu losowego wiersza, możesz uzyskać wynik niemal natychmiast. Problem polega na tym, jak odgadnąć wartość indeksu.

Następujące rozwiązanie działa na PostgreSQL 8.4:

explain analyze select * from cms_refs where rec_id in 
  (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
   from generate_series(1,10))
  limit 1;

Powyżej rozwiązania odgadniesz 10 różnych losowych wartości indeksu z zakresu 0 .. [ostatnia wartość id].

Liczba 10 jest dowolna - możesz użyć 100 lub 1000, ponieważ (zadziwiająco) nie ma to dużego wpływu na czas reakcji.

Jest też jeden problem - jeśli masz rzadkie identyfikatory, których możesz przegapić . Rozwiązaniem jest mieć plan tworzenia kopii zapasowych :) W tym przypadku czyste stare zamówienie przez losowe () zapytanie. Po połączeniu id wygląda następująco:

explain analyze select * from cms_refs where rec_id in 
    (select (random()*(select last_value from cms_refs_rec_id_seq))::bigint 
     from generate_series(1,10))
    union all (select * from cms_refs order by random() limit 1)
    limit 1;

Nie klauzula unii ALL . W takim przypadku, jeśli pierwsza część zwróci jakiekolwiek dane, NIGDY nie zostanie wykonana!

hegemon
źródło
1

Późno, ale dotarłem tutaj przez Google, więc dla potomności dodam alternatywne rozwiązanie.

Innym podejściem jest dwukrotne użycie TOP, przy naprzemiennych zamówieniach. Nie wiem, czy jest to „czysty SQL”, ponieważ wykorzystuje zmienną w TOP, ale działa w SQL Server 2008. Oto przykład, którego używam w stosunku do tabeli słów słownikowych, jeśli chcę losowe słowo.

SELECT TOP 1
  word
FROM (
  SELECT TOP(@idx)
    word 
  FROM
    dbo.DictionaryAbridged WITH(NOLOCK)
  ORDER BY
    word DESC
) AS D
ORDER BY
  word ASC

Oczywiście @idx to losowo generowana liczba całkowita, która zawiera się w przedziale od 1 do COUNT (*) w tabeli docelowej, włącznie. Jeśli Twoja kolumna jest zaindeksowana, również z niej skorzystasz. Kolejną zaletą jest to, że można go używać w funkcji, ponieważ NEWID () jest niedozwolony.

Na koniec powyższe zapytanie działa w około 1/10 czasu wykonania zapytania typu NEWID () w tej samej tabeli. RRMV.

alphadogg
źródło
1

Możesz także spróbować użyć new id()funkcji.

Wystarczy napisać zapytanie i użyć kolejności według new id()funkcji. To dość losowe.

Jai - gotaninterviewcall
źródło
1

Aby MySQL uzyskał losowy rekord

 SELECT name
  FROM random AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(id)
                        FROM random)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1

Więcej szczegółów http://jan.kneschke.de/projects/mysql/order-by-rand/

Sophy
źródło
Po przetestowaniu wielu odpowiedzi uważam, że jest to najlepsza. Wydaje się być szybki i za każdym razem wybiera dobrą liczbę losową. Wydaje się, że jest podobny do drugiej sugestii @GreyPanther powyżej, ale ta odpowiedź wybiera więcej liczb losowych.
Jeff Baker
1

Nie widziałem jeszcze tej zmiany w odpowiedziach. Miałem dodatkowe ograniczenie, gdzie musiałem, biorąc pod uwagę początkowe ziarno, aby wybrać ten sam zestaw wierszy za każdym razem.

W przypadku MS SQL:

Minimalny przykład:

select top 10 percent *
from table_name
order by rand(checksum(*))

Znormalizowany czas wykonania: 1,00

Przykład NewId ():

select top 10 percent *
from table_name
order by newid()

Znormalizowany czas wykonania: 1,02

NewId()jest nieznacznie wolniejszy niż rand(checksum(*)), więc możesz nie chcieć używać go do dużych zestawów płyt.

Wybór z początkowym nasionem:

declare @seed int
set @seed = Year(getdate()) * month(getdate()) /* any other initial seed here */

select top 10 percent *
from table_name
order by rand(checksum(*) % seed) /* any other math function here */

Jeśli musisz wybrać ten sam zestaw dla danego ziarna, wydaje się, że to działa.

klyd
źródło
1

W MSSQL (testowany na 11.0.5569) przy użyciu

SELECT TOP 100 * FROM employee ORDER BY CRYPT_GEN_RANDOM(10)

jest znacznie szybszy niż

SELECT TOP 100 * FROM employee ORDER BY NEWID()
David Knight
źródło
1

W SQL Server możesz łączyć TABLESAMPLE z NEWID (), aby uzyskać całkiem dobrą losowość i nadal mieć szybkość. Jest to szczególnie przydatne, jeśli naprawdę chcesz tylko 1 lub niewielką liczbę wierszy.

SELECT TOP 1 * FROM [table] 
TABLESAMPLE (500 ROWS) 
ORDER BY NEWID()
Chris Arbogast
źródło
1

W SQL Server 2012+ można użyć kwerendy FETCH OFFSET, aby zrobić to dla pojedynczego losowego wiersza

select  * from MyTable ORDER BY id OFFSET n ROW FETCH NEXT 1 ROWS ONLY

gdzie id to kolumna tożsamości, a n to żądany wiersz - obliczany jako liczba losowa między 0 a count () - 1 tabeli (offset 0 to przecież pierwszy wiersz)

Działa to z otworami w danych tabeli, o ile masz indeks do pracy dla klauzuli ORDER BY. Jest to również bardzo dobre dla losowości - gdy ćwiczysz, że się poddajesz, ale w innych metodach nie ma drobiazgów. Ponadto wydajność jest całkiem dobra, na mniejszym zestawie danych dobrze się trzyma, chociaż nie próbowałem poważnych testów wydajności w stosunku do kilku milionów wierszy.

gbjbaanb
źródło
0
 SELECT * FROM table ORDER BY RAND() LIMIT 1
Jeremy Ruten
źródło
Dziesięć lat temu (2005) jakiś facet powiedział, że używanie ORDER BY RAND()jest złe ...
trejder
0

Muszę się zgodzić z CD-MaN: użycie „ORDER BY RAND ()” będzie działało dobrze na małych stolikach lub gdy wykonasz SELECT tylko kilka razy.

Używam również techniki „num_value> = RAND () * ...”, a jeśli naprawdę chcę uzyskać losowe wyniki, mam specjalną „losową” kolumnę w tabeli, którą aktualizuję raz dziennie. To pojedyncze uruchomienie UPDATE zajmie trochę czasu (zwłaszcza, że ​​będziesz musiał mieć indeks w tej kolumnie), ale jest znacznie szybsze niż tworzenie liczb losowych dla każdego wiersza za każdym razem, gdy uruchamiany jest wybór.

BlaM
źródło
0

Bądź ostrożny, ponieważ TableSample nie zwraca losowej próbki wierszy. Kieruje zapytanie do losowej próbki stron o wielkości 8 KB, które składają się na wiersz. Następnie zapytanie jest wykonywane na podstawie danych zawartych na tych stronach. Ze względu na sposób grupowania danych na tych stronach (kolejność wstawiania itp.) Może to prowadzić do danych, które w rzeczywistości nie są przypadkową próbką.

Zobacz: http://www.mssqltips.com/tip.asp?tip=1308

Ta strona MSDN dla TableSample zawiera przykład generowania faktycznie losowej próbki danych.

http://msdn.microsoft.com/en-us/library/ms189108.aspx

Sean Turner
źródło
0

Wygląda na to, że wiele z wymienionych pomysłów nadal korzysta z funkcji zamawiania

Jeśli jednak używasz tabeli tymczasowej, możesz przypisać losowy indeks (jak sugeruje wiele rozwiązań), a następnie pobrać pierwszy, który jest większy niż dowolna liczba z zakresu od 0 do 1.

Na przykład (dla DB2):

WITH TEMP AS (
SELECT COMLUMN, RAND() AS IDX FROM TABLE)
SELECT COLUMN FROM TABLE WHERE IDX > .5
FETCH FIRST 1 ROW ONLY
DAVID
źródło
2
Po rozważeniu tego rozwiązania znalazłem zasadniczą wadę w mojej logice. Spowodowałoby to konsekwentnie zwracanie tych samych małych wartości ustawień, blisko początku tabeli, ponieważ zakładam, że jeśli byłby równomierny rozkład między 0 a 1, istnieje 50% szans, że pierwszy rząd spełni te kryteria.
DAVID,
0

Jest lepsze rozwiązanie dla Oracle zamiast korzystania z dbms_random.value, podczas gdy wymaga pełnego skanowania, aby uporządkować wiersze według dbms_random.value, a dla dużych tabel jest dość wolne.

Zamiast tego użyj tego:

SELECT *
FROM employee sample(1)
WHERE rownum=1
sev3ryn
źródło
0

W przypadku Firebird:

Select FIRST 1 column from table ORDER BY RAND()
Luigi04
źródło
0

W przypadku programu SQL Server 2005 i nowszych rozszerzenie odpowiedzi @ GreyPanther w przypadkach, gdy num_valuenie ma ciągłych wartości. Działa to również w przypadkach, gdy nie rozprowadziliśmy równomiernie zestawów danych i gdy num_valuenie jest liczbą, ale unikalnym identyfikatorem.

WITH CTE_Table (SelRow, num_value) 
AS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY ID) AS SelRow, num_value FROM table
) 

SELECT * FROM table Where num_value = ( 
    SELECT TOP 1 num_value FROM CTE_Table  WHERE SelRow >= RAND() * (SELECT MAX(SelRow) FROM CTE_Table)
)
Endri
źródło
-1

Pomocna może być funkcja losowa z sql. Również jeśli chcesz ograniczyć się do jednego wiersza, po prostu dodaj go na końcu.

SELECT column FROM table
ORDER BY RAND()
LIMIT 1
nvnvashisth
źródło