Jak losowo wybierać wiersze w SQL?

Używam MSSQL Server 2005. W moim db mam tabelę "customerNames", która ma dwie kolumny " Id "i" Name " i ok. 1000 wyników.

Tworzę funkcjonalność, w której za każdym razem muszę losowo wybierać 5 klientów. Czy ktoś może mi powiedzieć, jak utworzyć zapytanie, które otrzyma losowe 5 wierszy (Id i nazwa) za każdym razem, gdy zapytanie zostanie wykonane?

Author: Kate Gregory, 2009-02-24

9 answers

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

To powiedziawszy, wydaje się, że wszyscy przychodzą na tę stronę, aby uzyskać bardziej ogólną odpowiedź na twoje pytanie:

Wybór losowego wiersza w SQL

Wybierz losowy wiersz z MySQL:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

Wybierz losowy wiersz z PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Wybierz losowy wiersz z 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

Wybierz losowy wiersz z sqlite:

SELECT column FROM table 
ORDER BY RANDOM() LIMIT 1
 498
Author: Curtis Tasker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 21:19:04
SELECT TOP 5 Id, Name FROM customerNames ORDER BY NEWID()
 33
Author: Cody Caughlan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-24 06:21:37

W razie gdyby ktoś chciał mieć rozwiązanie PostgreSQL:

select id, name
from customer
order by random()
limit 5;
 8
Author: Barry Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-24 06:45:56

Być może Ta strona będzie pomocna.

Dla tych, którzy nie chcą klikać:

SELECT TOP 1 column FROM table
ORDER BY NEWID()
 7
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-24 06:21:20

Jest tu ładne rozwiązanie Microsoft SQL Server 2005. Zajmuje się problemem, w którym pracujesz z dużym zestawem wyników(nie pytanie, które znam).

Wybieranie wierszy losowo z dużej tabeli http://msdn.microsoft.com/en-us/library/cc441928.aspx

 5
Author: johnc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-23 12:17:51

Uznałem, że to działa najlepiej dla big data.

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

TABLESAMPLE(n ROWS) or TABLESAMPLE(n PERCENT) jest losowy, ale trzeba dodać TOP n, aby uzyskać prawidłowy rozmiar próbki.

Używanie NEWID() jest bardzo powolne na dużych stołach.

 3
Author: Billy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-15 23:08:59

SELECT * FROM TableName ORDER BY random () LIMIT 5;

 3
Author: Narendra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-25 07:49:41

Jeśli masz tabelę z milionami wierszy i zależy ci na wydajności, może to być lepsza odpowiedź:

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

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

 1
Author: Tohid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-03 22:14:37

Jest to stare pytanie, ale próba zastosowania nowego pola (nevid() lub ORDER BY rand ()) do tabeli z dużą liczbą wierszy byłaby zbyt kosztowna. Jeśli masz przyrostowe, unikalne identyfikatory (i nie masz żadnych dziur), bardziej wydajne będzie obliczenie x # identyfikatorów, które mają być wybrane, zamiast stosowania identyfikatora GUID lub podobnego do każdego pojedynczego wiersza, a następnie wzięcia górnego x#.

DECLARE @maxValue int = (select max(id) from [TABLE])
DECLARE @minValue int = (select min(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)

Jeśli chcesz wybrać o wiele więcej wierszy, przyjrzałbym się wypełnianiu # tempTable z ID i kilkoma wartościami rand (), a następnie używając każdej wartości rand () do skalowania do wartości min-max. W ten sposób nie musisz definiować wszystkich @randomId1...N parametry. Poniżej zamieściłem przykład użycia cte do wypełnienia początkowej tabeli.

DECLARE @NumItems int = 100;

DECLARE @maxValue int = (select max(id) from [TABLE])
DECLARE @minValue int = (select min(id) from [TABLE])

with cte (n) as (select 1 union all select n+1 from cte where n < @NumItems)
select cast( ((@maxValue + 1) - @minValue) * rand(cast(newid() as varbinary(100))) + @minValue as int) as tp into #Nt
from 
cte
select * from  #Nt ntt
inner join [TABLE] i 
        on i.id = ntt.tp
drop table #Nt
 1
Author: RIanGillis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-18 02:30:41