Silakan lihat kode ini:
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');
Sekarang, setiap kali Anda menjalankan ini
select *,
( select top 1 val from #t1 order by NEWID()) rnd
from #t1 order by 1;
Anda akan mendapatkan hasil dengan semua baris memiliki nilai acak yang sama. misalnya
id val rnd
----------- ---------- ----------
1 a b
2 b b
3 c b
4 d b
Saya tahu cara menggunakan kursor untuk mengulang lemparan baris dan mendapatkan nilai acak yang berbeda, tetapi itu bukan pemain.
Solusi cerdas untuk ini adalah
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
Tapi saya menyederhanakan kueri. Permintaan yang sebenarnya lebih mirip
select *,
( select top 1 val from t2 where t2.x <> t1.y order by NEWID()) rnd
from t1 order by 1;
dan solusi sederhana tidak cocok. Saya mencari cara untuk memaksa evaluasi berulang
( select top 1 val from #t1 order by NEWID()) rnd
tanpa menggunakan kursor.
Edit: Output yang diinginkan:
mungkin 1 panggilan
id val rnd
----------- ---------- ----------
1 a c
2 b c
3 c b
4 d a
dan panggilan kedua
id val rnd
----------- ---------- ----------
1 a a
2 b d
3 c d
4 d b
Nilai untuk setiap baris harus berupa nilai acak yang independen dari baris lainnya
Ini adalah versi kode kursor:
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
sumber
sumber
Jawaban:
Subquery dievaluasi satu kali jika memungkinkan. Saya tidak dapat mengingat apa yang disebut "fitur" (lipat?) Maaf.
Hal yang sama berlaku untuk fungsi GETDATE dan RAND. NEWID dievaluasi baris demi baris karena secara intrinsik merupakan nilai acak dan tidak boleh menghasilkan nilai yang sama dua kali.
Teknik yang biasa digunakan adalah menggunakan NEWID sebagai input untuk CHECKSUM atau sebagai seed untuk RAND
Untuk nilai acak per baris:
Jika Anda ingin pesanan acak:
Jika Anda ingin pesanan acak dengan urutan baris juga. Pesanan ActualOrder di sini dipertahankan tanpa memperhatikan urutan resultset
Edit:
Dalam hal ini, kita dapat menyatakan persyaratan sebagai:
Ini berbeda dengan apa yang saya tawarkan di atas yang hanya memesan ulang baris dengan berbagai cara
Jadi, saya akan mempertimbangkan LINTAS BERLAKU. Klausa WHERE klausa mengevaluasi baris demi baris dan menghindari masalah "melipat" dan memastikan bahwa val dan rnd selalu berbeda. CROSS APPLY juga bisa menskalakan dengan cukup baik
sumber