Як довільно вибрати рядки в SQL?


226

Я використовую MSSQL Server 2005. У моєму db у мене є таблиця "Імена клієнта", у якій є два стовпці "Id" та "Name" та прибл. 1000 результатів.

Я створюю функціонал, коли мені щоразу доводиться вибирати 5 клієнтів випадковим чином. Хто-небудь може сказати мені, як створити запит, який отримуватиме випадкові 5 рядків (Id та Name) кожного разу, коли запит виконується?


Випадкові
випадки

2
Залежить від того, скільки випадкових випадків ви хочете. Дивіться: msdn.microsoft.com/en-us/library/aa175776(SQL.80).aspx для порівняння NEW_ID проти RAND ()
Shannon Severance

Відповіді:


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

Але, мабуть, всі приходять на цю сторінку для отримання більш загальної відповіді на ваше запитання:

Вибір випадкового рядка в SQL

Виберіть випадковий рядок за допомогою MySQL:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

Виберіть випадковий рядок за допомогою PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Виберіть випадковий рядок за допомогою Microsoft SQL Server:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

Виберіть випадковий рядок з IBM DB2

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

Виберіть випадковий запис за допомогою Oracle:

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

Виберіть випадковий рядок з sqlite:

SELECT column FROM table 
ORDER BY RANDOM() LIMIT 1

3
+1 для розміщення відповідей безпосередньо на SO замість посилання на зовнішній сайт (наприклад, прийняту відповідь), який міг би знизитися, коли майбутні користувачі переглянуть це питання.
Рей Чжоу

17
Чи стає це дуже дорого на великих таблицях, де кожен рядок отримує випадкове число, а потім сортується великий набір невкладених випадкових чисел?
Андрій

Це, мабуть, очевидно для більшості людей, але мені це було не очевидно ... наступний запит не отримає нового випадкового значення для кожного рядка: update tbl_vouchers set tbl_UsersID = (select top(1) id from tbl_Users order by NEWID()) - редагувати: я не можу отримати форматування для роботи в коментарях :(
Mir

Ти геній! Я так тебе ненавиджу, бо я не бачив цього, поки не пішов і написав шалено довгий запит із підзапросами та номерами рядків.
greenkode

5
Попередження: Для великих баз даних цей метод матиме погані показники. Чи можете ви уявити час, який знадобиться для генерації випадкових значень для кожного ряду, якщо база даних має мільйон даних? Ви можете отримати більше інформації про та кращу альтернативу тут .
Френсіс Нгуюкам


11

У випадку, якщо хтось захоче рішення PostgreSQL:

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

Ця відповідь хороша для PostgreSQL, їй не потрібно обмеження.
псевдонім

9

Можливо, цей сайт буде корисним.

Для тих, хто не хоче натискати:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

2
мав би принаймні замінити 1 на 5 :)
Роман м

7

Тут є приємне рішення для Microsoft SQL Server 2005. Займається проблемою, коли ви працюєте з великим набором результатів (не те питання, яке я знаю).

Вибір випадкових рядків з великої таблиці http://msdn.microsoft.com/en-us/library/cc441928.aspx


5

Якщо у вас є таблиця з мільйонами рядків і ви дбаєте про продуктивність, це може бути кращою відповіддю:

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

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


Зауважте, що для цього буде виділено приблизно 10% рядків у таблиці. Якщо вам потрібно вибрати точну кількість рядків або принаймні N рядків, такий підхід не буде працювати.
LarsH

4

Це старе питання, але спроба застосувати нове поле (або NEWID () або ORDER BY rand ()) до таблиці з великою кількістю рядків було б надмірно дорогим. Якщо у вас є додаткові, унікальні ідентифікатори (і у них немає жодних отворів), то ефективніше буде обчислити вибраний X # ідентифікаторів, а не застосовувати GUID або подібний до кожного ряду, а потім приймати верхній X # з.

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)

Якби ви хотіли вибрати ще багато рядків, я би роздивився заповнення #tempTable з ідентифікатором та купою значень rand (), а потім використовуючи кожне значення rand () для масштабування до мінімальних значень. Таким чином, вам не потрібно визначати всі параметри @ randomId1 ... n. Нижче я включив приклад використання CTE для заповнення початкової таблиці.

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, запропонована вами редакція порушила випадковий вибір. Використання min () та max (), застосованих до таблиці dbo.Tally64k не дозволить користувачеві вибрати рядок з ідентифікатором pk> 65556.
RIanGillis,

Зміна назви таблиці була просто артефактом тестування. Фактична назва таблиці не має значення, якщо використовується правильна таблиця. min () та max () можна запитувати в одному запиті, а не в двох, що я намагався показати.
Близький

@Protiguous Ах, я бачу, що зараз я розгубився, тому що ви використовували 0-65k під час виконання min-max, але не пізніше. Після вашої останньої редакції я насправді хотів запитати вас про наслідки для змін, які ви внесли, оскільки налаштування продуктивності - це один із моїх інтересів, і, здавалося б, безглузді рішення, наприклад, на якій стороні рівняння ви підписуєте щось, може насправді мати суттєвий вплив - - Чи те ж саме стосуватиметься 5 дзвінків SET @ randomId ##? Або це інше, тому що це не ВИБІР ВІД фактичної таблиці?
RIanGillis

Я не впевнений, що розумію ваше запитання. Ви запитуєте, чому існує 5 SET замість всього 1 SELECT @ id1 = rand (), @ id2 = rand () ..? Це тому, що кілька викликів до rand () в 1 операторі дають однаковий результат, отже, відокремлений SET. (Я вважаю, що rand () на SQL Server є детермінованою функцією. Я здогадуюсь, що 1 набір від 5 набір залежить від наносекундного діапазону.
Попередній

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

Старе запитання, але ця відповідь не побігла для мене в Oracle.
Ведмідь

SELECT * FROM (SELECT * FROM таблиця ORDER BY DBMS_RANDOM.VALUE) WHERE rownum <число; @ Постарайтеся спробувати це
Нарендра

3

Я виявив, що це найкраще працює для великих даних.

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

TABLESAMPLE(n ROWS) or TABLESAMPLE(n PERCENT)є випадковим, але потрібно додати значення, TOP nщоб отримати правильний розмір вибірки.

Використання NEWID()на великих столах дуже повільне.


0

Як я пояснював у цій статті , для переміщення набору результатів SQL вам потрібно використовувати виклик функції, що залежить від бази даних.

Зауважте, що сортування великого набору результатів за допомогою функції RANDOM може виявитися дуже повільним, тому переконайтеся, що ви робите це на невеликих наборах результатів.

Якщо у вас є перетасувати великий набір результатів і обмежити його пізніше, то краще використовувати що - щось на зразок OracleSAMPLE(N) або TABLESAMPLEв SQL Server або PostgreSQL замість випадкової функції в ORDER BY пропозиції.

Отже, якщо ми маємо таку таблицю бази даних:

введіть тут опис зображення

І наступні рядки в songтаблиці:

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

Oracle

Для Oracle вам потрібно використовувати DBMS_RANDOM.VALUEфункцію, як проілюстровано наступним прикладом:

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

Під час запуску вищезгаданого запиту SQL в Oracle ми отримаємо наступний набір результатів:

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

Зауважте, що пісні перераховані у випадковому порядку завдяки DBMS_RANDOM.VALUEвиклику функції, використовуваному пунктом ORDER BY.

SQL Server

На SQL Server потрібно використовувати NEWIDфункцію, як проілюстровано наступним прикладом:

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

Під час виконання вищезазначеного запиту SQL на SQL Server ми отримаємо наступний набір результатів:

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

Зауважте, що пісні перераховані у випадковому порядку завдяки NEWIDвиклику функції, використовуваному пунктом ORDER BY.

PostgreSQL

На PostgreSQL потрібно використовувати randomфункцію, як проілюстровано наступним прикладом:

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

Запускаючи вищезазначений запит SQL на PostgreSQL, ми отримаємо наступний набір результатів:

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

Зауважте, що пісні перераховані у випадковому порядку завдяки randomвиклику функції, використовуваному пунктом ORDER BY.

MySQL

На MySQL потрібно використовувати RANDфункцію, як проілюстровано наступним прикладом:

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

Під час виконання вищезазначеного запиту SQL на MySQL ми отримаємо наступний набір результатів:

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

Зауважте, що пісні перераховані у випадковому порядку завдяки RANDвиклику функції, використовуваному пунктом ORDER BY.


0

Якщо ви використовуєте велику таблицю і хочете отримати доступ до 10 відсотків даних, виконайте наступну команду: SELECT TOP 10 PERCENT * FROM Table1 ORDER BY NEWID();

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.