loading..
Русский    English
14:00
листать

Случайная выборка строк из таблицы в SQL Server стр. 2

Попробуем теперь применить функцию RAND для нашей задачи, а именно, для выдачи двух случайным образом выбранных моделей:

Консоль
Выполнить
  1. SELECT TOP 2 model
  2. FROM Product
  3. ORDER BY RAND(model);

Получаем первые две модели в порядке возрастания их номеров. Вот где проявилась псевдослучайность. Посмотрим, что за случайные числа мы имеем:

Консоль
Выполнить
  1. SELECT model, RAND(model) rnd
  2. FROM Product
  3. ORDER BY rnd;

Для краткости приведу их не все:

Model rnd
1121 0.73446092102210758
1232 0.73652918083176777
1233 0.73654781380302592
1260 0.73705090402699736
1276 0.7373490315671285
1288 0.73757262722222694
1298 0.73775895693480897

Я не знаю, какой алгоритм используется для вычисления случайного числа, однако могу утверждать, что функция RAND ведет себя монотонно в данном диапазоне номеров моделей. Потому у нас ничего и не получилось.

В  Электронная документация SQL Server Books OnlineBOL приводится пример генерации последовательности случайных чисел с использованием системного времени, чтобы динамически менять начальное значение. Вот он:

Консоль
Выполнить
  1. SELECT RAND( (DATEPART(mm, GETDATE()) * 100000 )
  2. + (DATEPART(ss, GETDATE()) * 1000 )
  3. + DATEPART(ms, GETDATE())
  4. );

Однако в таком виде запрос может быть задействован только в медленно выполняющихся пакетах, чтобы неоднократное выполнение запроса происходило не чаще, чем минимальная единица времени, применяемая в запросе (миллисекунды). Очевидно, что использование этой функции в выборке модели не будет отвечать этому условию. Однако если умножить аргумент на некоторый уникальный идентификатор, то мы можем добиться успеха (это решение было предложено Гершовичем В.И.):

Консоль
Выполнить
  1. SELECT model, RAND(model*(DATEPART(mm, GETDATE()) * 100000 )
  2. + (DATEPART(ss, GETDATE()) * 1000 )
  3. + DATEPART(ms, GETDATE())
  4. )
  5. FROM Product
  6. ORDER BY model;

Однако тут есть одна проблема, связанная с тем, что аргументом функции RAND является целое число. Поэтому если мы превысим максимально допустимое значение для целого числа (для  Cистема управления реляционными базами данных (СУБД), разработанная корпорацией Microsoft. Язык структурированных запросов) — универсальный компьютерный язык, применяемый для создания, модификации и управления данными в реляционных базах данных. SQL Server оно составляет 2^31-1 или 2 147 483 647), то получим следующее сообщение об ошибке:

Arithmetic overflow error converting expression to data type int.

(«Ошибка переполнения при преобразовании выражения к типу данных int».)

В этом можно убедиться, выполнив вышеприведенный запрос на сайте. Ошибка возникает где-то на номерах моделей, превышающих 2000. В аналогичных случаях нужен еще нормирующий множитель, например,

  1. CASE
  2. WHEN model < 2000
  3. THEN model
  4. ELSE model/10+model % 10
  5. END

Здесь добавление model % 10 (остаток от деления на 10) делается для того, чтобы не потерять значащие цифры; в противном случае мы можем получить одинаковые значения для моделей, номера которых отличаются на единицы.

В окончательном виде решение будет выглядеть так (естественно, сортировку нужно делать по rnd, а не по model, которую мы оставили для наглядности результата).

Решение 8.8.3

Консоль
Выполнить
  1. SELECT model,
  2. RAND(CASE
  3. WHEN model < 2000
  4. THEN model
  5. ELSE model/10+model % 10
  6. END *
  7. (DATEPART(mm, GETDATE()) * 100000 )
  8. + (DATEPART(ss, GETDATE()) * 1000 )
  9. + DATEPART(ms, GETDATE())
  10. ) rnd
  11. FROM Product
  12. ORDER BY model;

А теперь сравните результаты:

model Rnd
1121 0.40138073102287292
1232 0.48719939613580043
1233 0.98346802618590112
1260 0.38272122312416984
1276 0.3230194099746666
1288 0.27824305011253919
1298 0.24092941689409972

Вывод. Для решения рассматриваемой задачи проще и надежней использовать функцию NEWID(), которая гарантирует уникальность значений. Однако эти значения не являются числовыми. Поэтому там, где нужно получить именно число, следует обратить внимание на функцию RAND().

Bookmark and Share
Страницы: 1 2
Тэги:
ALL AND AUTO_INCREMENT AVG battles CASE CAST CHAR CHARINDEX CHECK classes COALESCE CONSTRAINT Convert COUNT CROSS APPLY CTE DATEADD DATEDIFF DATENAME DATEPART DATETIME DDL DEFAULT DELETE DISTINCT DML EXCEPT EXISTS EXTRACT FOREIGN KEY FROM FULL JOIN GROUP BY Guadalcanal HAVING IDENTITY IN INFORMATION_SCHEMA INNER JOIN insert INTERSECT IS NOT NULL IS NULL ISNULL laptop LEFT LEFT OUTER JOIN LEN maker Больше тэгов
Учебник обновлялся
месяц назад
https://exchangesumo.com/obmen/BTC-PXMUSD-sort
©SQL-EX,2008 [Развитие] [Связь] [О проекте] [Ссылки] [Team]
Перепечатка материалов сайта возможна только с разрешения автора.