Случайный выбор SQL Server с использованием начального числа

Я хочу добавить столбец в свою таблицу со случайным числом, используя seed. Если я использую RAND:

select *, RAND(5) as random_id from myTable

Я получаю одинаковое значение (например, 0,943597390424144) для всех строк в столбце random_id. Я хочу, чтобы это значение было разным для каждой строки - и каждый раз, когда я буду передавать ему значение 0,5 (например), это будут те же значения снова (поскольку семя должно работать...).

Как я могу это сделать?

(Например, в PostrgreSql я могу написать

SELECT setseed(0.5); SELECT t.* , random() as random_id FROM myTable t

И я буду получать разные значения в каждой строке. )


Изменить:

После того, как я увидел комментарии здесь, мне удалось как-то это решить, но это совсем не эффективно. Если у кого-то есть идея как его улучшить - будет здорово. Если нет - мне придется найти другой способ.

Я использовал основную идею примера из здесь.

Создание временной таблицы с пустым начальным значением:

select * into t_myTable  from (
select t.*, -1.00000000000000000 as seed
       from myTable t
       ) as temp

Добавление случайного числа для каждого начального значения, по одной строке за раз (это плохая часть...):

USE CPatterns;
GO
DECLARE @seed float;
DECLARE @id int;
DECLARE VIEW_CURSOR CURSOR FOR
select id
from t_myTable t;
OPEN VIEW_CURSOR;
FETCH NEXT FROM VIEW_CURSOR
into @id;
set @seed = RAND(5);

WHILE @@FETCH_STATUS = 0
   BEGIN
      set @seed = RAND();
         update t_myTable set seed = @seed where id = @id

      FETCH NEXT FROM VIEW_CURSOR
         into @id;

   END;
CLOSE VIEW_CURSOR;
DEALLOCATE VIEW_CURSOR;
GO

Создание представления с использованием начального значения и упорядочения по нему

create view my_view AS 
select row_number() OVER (ORDER BY seed, id) AS  source_id ,t.*
       from t_myTable t

person yishaiz    schedule 16.09.2014    source источник
comment
AFIK, вы не можете эмулировать поведение setseed, т.е. постоянно создавать одни и те же случайные числа, но чтобы получить другое случайное число для каждой строки, а не повторять одно и то же, вы можете использовать RAND(CHECKSUM(NEWID())) - например, SELECT RAND(CHECKSUM(NEWID())) FROM sys.all_objects   -  person GarethD    schedule 16.09.2014
comment
Я рекомендую пройти по этой ссылке - blogs.lessthandot.com/index.php/DataMgmt/DataDesign/   -  person Krishnraj Rana    schedule 16.09.2014
comment
@GarethD, я должен постоянно создавать одни и те же случайные числа, поэтому я опубликовал обновление, пожалуйста, посмотрите.   -  person yishaiz    schedule 23.09.2014
comment
Я немного запутался. В вашем примере используется rand(0.5), но в SQL Server rand() принимает только целочисленное начальное число.   -  person Gordon Linoff    schedule 23.09.2014
comment
@ Гордон Линофф ... Извините, я пытался соответствовать примеру PostgreSql, поэтому я также изменил значение для SQL Server. Я отредактировал вопрос.   -  person yishaiz    schedule 23.09.2014


Ответы (4)


Я думаю, что самый простой способ получить повторяющийся случайный идентификатор в таблице — использовать row_number() или фиксированный id в каждой строке. Позвольте мне предположить, что у вас есть столбец с именем id с разными значениями в каждой строке.

Идея состоит в том, чтобы просто использовать это как семя:

select rand(id*1), as random_id
from mytable;

Обратите внимание, что начальным значением для идентификатора является целое число, а не число с плавающей запятой. Если вам нужно начальное число с плавающей запятой, вы можете что-то сделать с checksum():

select rand(checksum(id*0.5)) as random_id
. . .

Если вы делаете это для выборки (где вы, например, скажете random_id < 0.1 для выборки 10%, то я часто использую арифметику по модулю для row_number():

with t as (
      select t.* row_number() over (order by id) as seqnum
      from mytable t
     )
select *
from t
where ((seqnum * 17 + 71) % 101) < 0.1

Это возвращает около 10% чисел (хорошо, действительно 10/101). И вы можете настроить семпл, повозившись с константами.

person Gordon Linoff    schedule 16.09.2014
comment
Привет, проблема в том, что я хочу использовать начальное/случайное число для заказа. Я попробовал select rand(id*1), as random_id from mytable;. но это не помогает для упорядочения - потому что кажется, что RAND (1) ‹ RAND (2) ‹ RAND (3) ‹ .... Так что это не помогает для упорядочения, потому что порядок остается прежним. . - person yishaiz; 22.09.2014
comment
@yishaiz . . . Я понятия не имел, что SQL Server был сломан таким образом. Большое спасибо, что указали на это. По крайней мере, генератор псевдослучайных чисел должен работать. - person Gordon Linoff; 22.09.2014
comment
генератора псевдослучайных чисел мне недостаточно, поэтому я выложил обновление, пожалуйста, посмотрите. - person yishaiz; 23.09.2014

Кто-то предложил аналогичный запрос с использованием newid(), но я даю вам решение, которое работает для меня.

Есть обходной путь, использующий newid() вместо rand, но он дает тот же результат. Вы можете выполнить его индивидуально или как столбец в столбце. Это приведет к случайному значению для каждой строки, а не к одному и тому же значению для каждой строки в операторе выбора. Если вам нужно случайное число от 0 до N, просто измените 100 на нужное число.

SELECT TOP 10 [Flag forca]
,1+ABS(CHECKSUM(NEWID())) % 100 AS RANDOM_NEWID
,RAND() AS  RANDOM_RAND
FROM PAGSEGURO_WORK.dbo.jobSTM248_tmp_leitores_iso

Результат

person Jader Gabriel Soares de Arruda    schedule 19.02.2019

Итак, на случай, если кто-то когда-нибудь захочет, вот что я в конце концов сделал.

Я генерирую случайные начальные значения на стороне сервера (Java в моем случае), а затем создаю таблицу с двумя столбцами: id и сгенерированный random_id. Теперь я создаю представление как inner join между таблицей и исходными данными.

Сгенерированный SQL выглядит примерно так:

CREATE TABLE SEED_DATA(source_id INT PRIMARY KEY, random_id float NOT NULL);
select Rand(5); 
insert into SEED_DATA values(1,Rand());
insert into SEED_DATA values(2, Rand());
insert into SEED_DATA values(3, Rand());
.
.
.
insert into SEED_DATA values(1000000, Rand());

и

CREATE VIEW DATA_VIEW
as  
    SELECT row_number() OVER (ORDER BY random_id, id) AS source_id,column1,column2,...
    FROM 
        ( select * from SEED_DATA tmp 
          inner join my_table i on tmp.source_id = i.id) TEMP 

Кроме того, я создаю случайные числа партиями, по 10 000 или около того в каждой партии (может быть больше), чтобы они не сильно нагружали сервер, и для каждой партии я вставляю их в таблицу в отдельном выполнении.

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

Мой собственный вывод из этой истории заключается в том, что SQL Server иногда действительно раздражает...

person yishaiz    schedule 29.09.2014

Вы можете преобразовать случайное число из семени:

rand(row_number over (order by ___, ___,___))

Затем введите это как varchar, затем используйте последние 3 символа в качестве другого семени. Это даст вам хорошее случайное значение:

rand(right(cast(rand(row_number() over(x,y,x)) as varchar(15)), 3)
person CDenby    schedule 01.07.2017