Czy istnieje zwięzły sposób na pobranie losowego rekordu z tabeli serwera sql?
Chciałbym randomizować moje dane z testów jednostkowych, więc szukam prostego sposobu na wybranie losowego identyfikatora z tabeli. W języku angielskim opcja select to „Wybierz jeden identyfikator z tabeli, gdzie identyfikator jest liczbą losową między najniższym identyfikatorem w tabeli a najwyższym identyfikatorem w tabeli”.
Nie mogę znaleźć sposobu na zrobienie tego bez uruchamiania zapytania, testowania wartości null, a następnie ponownego uruchamiania, jeśli jest to wartość null.
Pomysły?
sql-server
tsql
random
Jeremy
źródło
źródło
Odpowiedzi:
tak
SELECT TOP 1 * FROM table ORDER BY NEWID()
Wyjaśnienie
Dla
NEWID()
każdego wiersza jest generowany znak, a tabela jest następnie sortowana według niego. Zwracany jest pierwszy rekord (tj. Rekord z „najniższym” identyfikatorem GUID).Uwagi
Identyfikatory GUID są generowane jako liczby pseudolosowe od wersji czwartej:
- Przestrzeń nazw URN Universally Unique IDentifier (UUID) - RFC 4122
Alternatywa
SELECT TOP 1 * FROM table ORDER BY RAND()
nie zadziała tak, jak mogłoby się wydawać.RAND()
zwraca jedną wartość na zapytanie, więc wszystkie wiersze będą miały tę samą wartość.Chociaż wartości GUID są pseudolosowe, będziesz potrzebować lepszego PRNG dla bardziej wymagających aplikacji.
Typowa wydajność to mniej niż 10 sekund dla około 1 000 000 rzędów - oczywiście w zależności od systemu. Pamiętaj, że nie można trafić w indeks, więc wydajność będzie stosunkowo ograniczona.
źródło
W przypadku większych tabel można również użyć
TABLESAMPLE
tego, aby uniknąć skanowania całej tabeli.SELECT TOP 1 * FROM YourTable TABLESAMPLE (1000 ROWS) ORDER BY NEWID()
ORDER BY NEWID
Jest nadal wymagane, aby uniknąć właśnie powracających wiersze, które pojawiają się najpierw na stronie danych.Liczbę, której należy użyć, należy starannie dobrać pod kątem rozmiaru i definicji tabeli, a jeśli nie zostanie zwrócony żaden wiersz, można rozważyć zastosowanie logiki ponawiania. Tutaj omówiono matematykę, która za tym stoi i dlaczego ta technika nie jest odpowiednia dla małych tabel
źródło
TOP 1
nie ma znaczenia, czy wiersze na tej samej stronie są skorelowane, czy nie. Wybierasz tylko jednego z nich.Wypróbuj również swoją metodę, aby uzyskać losowy identyfikator między MIN (Id) a MAX (Id), a następnie
SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid
Zawsze dostaniesz jeden wiersz.
źródło
Jeśli chcesz wybierać duże dane, najlepszym sposobem, jaki znam, jest:
SELECT * FROM Table1 WHERE (ABS(CAST( (BINARY_CHECKSUM (keycol1, NEWID())) as int)) % 100) < 10
Źródło: MSDN
źródło
Chciałem ulepszyć metody, które wypróbowałem i trafiłem na ten post. Zdaję sobie sprawę, że jest stara, ale ta metoda nie jest wymieniona. Tworzę i stosuję dane testowe; to pokazuje metodę "adresu" w SP wywołanej z @st (stan dwóch znaków)
Create Table ##TmpAddress (id Int Identity(1,1), street VarChar(50), city VarChar(50), st VarChar(2), zip VarChar(5)) Insert Into ##TmpAddress(street, city, st, zip) Select street, city, st, zip From tbl_Address (NOLOCK) Where st = @st -- unseeded RAND() will return the same number when called in rapid succession so -- here, I seed it with a guaranteed different number each time. @@ROWCOUNT is the count from the most recent table operation. Set @csr = Ceiling(RAND(convert(varbinary, newid())) * @@ROWCOUNT) Select street, city, st, Right(('00000' + ltrim(zip)),5) As zip From ##tmpAddress (NOLOCK) Where id = @csr
źródło
SELECT * FROM Sales.SalesOrderDetail WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float) / CAST (0x7fffffff AS int)
Jest to dokładniej wyjaśnione poniżej:
źródło