Пожалуйста, посмотрите на этот код:
create table #t1(
id int identity (1,1),
val varchar(10)
);
insert into #t1 values ('a');
insert into #t1 values ('b');
insert into #t1 values ('c');
insert into #t1 values ('d');
Теперь, когда вы выполняете это
select *,
( select top 1 val from #t1 order by NEWID()) rnd
from #t1 order by 1;
вы получите результат, где все строки имеют одинаковое случайное значение. например
id val rnd
----------- ---------- ----------
1 a b
2 b b
3 c b
4 d b
Я знаю способ использования курсора для циклического отбрасывания строк и получения разных случайных значений, но это не является производительным.
Умное решение этого
select t1.id, t1.val, t2.val
from #t1 t1
join (select *, ROW_NUMBER() over( order by NEWID()) lfd from #t1) as t2 on t1.id = t2.lfd
Но я упростил запрос. Реальный запрос больше похож на
select *,
( select top 1 val from t2 where t2.x <> t1.y order by NEWID()) rnd
from t1 order by 1;
и простое решение не подходит. Я ищу способ заставить повторную оценку
( select top 1 val from #t1 order by NEWID()) rnd
без использования курсоров.
Изменить: Требуемый вывод:
возможно 1 звонок
id val rnd
----------- ---------- ----------
1 a c
2 b c
3 c b
4 d a
и второй звонок
id val rnd
----------- ---------- ----------
1 a a
2 b d
3 c d
4 d b
Значение для каждой строки просто должно быть случайным значением, независимым от других строк
Вот версия курсора кода:
CREATE TABLE #res ( id INT, val VARCHAR(10), rnd VARCHAR(10));
DECLARE @id INT
DECLARE @val VARCHAR(10)
DECLARE c CURSOR FOR
SELECT id, val
FROM #t1
OPEN c
FETCH NEXT FROM c INTO @id, @val
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO #res
SELECT @id, @val, ( SELECT TOP 1 val FROM #t1 ORDER BY NEWID()) rnd
FETCH NEXT FROM c INTO @id, @val
END
CLOSE c
DEALLOCATE c
SELECT * FROM #res
sql-server
sql-server-2005
bernd_k
источник
источник
Ответы:
Подзапрос оценивается один раз, если это возможно. Я не могу вспомнить, как называется «фальшивка» (сворачивание?).
То же самое относится к функциям GETDATE и RAND. NEWID оценивается построчно, потому что это по сути случайное значение и никогда не должно генерировать одно и то же значение дважды.
Обычные методы - использовать NEWID в качестве входных данных для CHECKSUM или в качестве начального числа для RAND
Для случайных значений в строке:
Если вы хотите случайный порядок:
Если вы хотите случайный порядок с порядком строк тоже. Порядок ActualOrder здесь сохраняется независимо от порядка набора результатов
Редактировать:
В этом случае мы можем сформулировать требование как:
Это отличается от того, что я предложил выше, который просто переупорядочивает строки различными способами.
Итак, я бы рассмотрел CROSS APPLY. Предложение WHERE вынуждает вычислять строку за строкой, избегая проблемы «сворачивания» и гарантируя, что val и rnd всегда будут разными. CROSS APPLY тоже может хорошо масштабироваться
источник