SELECT ifadesindeki her bir satıra nasıl farklı rastgele değerler atayabilirim?


11

Lütfen şu koda bakın:

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

Şimdi, bunu her çalıştırdığınızda

select *, 
    ( select top 1 val from #t1 order by NEWID()) rnd 
from #t1 order by 1;

tüm satırların aynı rastgele değere sahip olduğu bir sonuç alırsınız. Örneğin

id          val        rnd
----------- ---------- ----------
1           a          b
2           b          b
3           c          b
4           d          b

Ben imleç kullanarak satır atmak ve farklı rastgele değerler almak için bir yol biliyorum, ama bu performans değil.

Bunun akıllıca bir çözümü

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 

Ama sorguyu basitleştirdim. Gerçek sorgu daha çok

select *, 
    ( select top 1 val from t2 where t2.x <> t1.y order by NEWID()) rnd 
from t1 order by 1;

ve basit çözüm uymuyor. Tekrar tekrar değerlendirmeyi zorlamanın bir yolunu arıyorum

( select top 1 val from #t1 order by NEWID()) rnd 

imleç kullanmadan.

Düzenleme: İstenen çıktı:

belki 1 çağrı

id          val        rnd
----------- ---------- ----------
1           a          c
2           b          c
3           c          b
4           d          a

ve ikinci bir çağrı

id          val        rnd
----------- ---------- ----------
1           a          a
2           b          d
3           c          d
4           d          b

Her satırın değeri diğer satırlardan bağımsız rastgele bir değer olmalıdır

İşte kodun imleç sürümü:

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

Mükemmel çıktınız ne olur lütfen? belki bir şey eksik
gbn


Yani rnd ve val her sırada her zaman farklı mıdır? "Rastgele" olsaydı, bazen aynı olurdu. Ayrıca, belirtilen 2 çağrınızda rnd'nin sütunda tüm değerleri olmaması önemli midir?
gbn

Büyük bir gerçek veri havuzundan küçük ila orta rastgele bir gösteri oluşturmak için kullanılır. Evet, tekrar gönderilmesine izin verilir.
bernd_k

Yanıtlar:


11

Alt sorgu mümkünse bir kez değerlendirilir. "Özellik" (katlanır?) Ne denir üzgünüm hatırlamıyorum.

Aynısı GETDATE ve RAND işlevleri için de geçerlidir. NEWID, satır içi olarak değerlendirilir, çünkü özünde rastgele bir değerdedir ve asla aynı değeri iki kez oluşturmamalıdır.

Genel teknikler NEWS kullanımını CHECKSUM'a girdi olarak veya RAND'a tohum olarak kullanmaktır

Satır başına rastgele değerler için:

SELECT
   co1l, col2,
   ABS(CHECKSUM(NEWID())) AS Random1,
   RAND(CHECKSUM(NEWID())) AS Random2
FROM
   MyTable

Rastgele sipariş istiyorsanız:

SELECT
   co1l, col2
FROM
   MyTable
ORDER BY
   NEWID()

Bir sıra sırası ile rastgele sipariş istiyorsanız. Buradaki sipariş sırası, sonuç kümesinin sırasına bakılmaksızın korunur

SELECT
   id, val,
   ROWNUMBER() OVER (ORDER BY id) AS id
FROM
   #t1
ORDER BY
   NEWID()

Düzenle:

Bu durumda, gereksinimi şöyle söyleyebiliriz:

  1. kümedeki her satır için kümeden herhangi bir rastgele değer döndürür
  2. rastgele değer herhangi bir satırdaki gerçek değerden farklı olacaktır

Bu, satırları çeşitli şekillerde yeniden sipariş eden yukarıda sunduğumdan farklı

Bu yüzden, ÇAPRAZ UYGULAMAYI düşünürüm. WHERE yan tümcesi kuvveti satır satır değerlendirir ve "katlama" sorununu önler ve val ve rnd'nin her zaman farklı olmasını sağlar. ÇAPRAZ UYGULAMA da oldukça iyi ölçeklenebilir

SELECT
   id, val, R.rnd
FROM
   #t1 t1
   CROSS APPLY
   (SELECT TOP 1 val as rnd FROM #t1 t2 WHERE t1.val <> t2.val ORDER BY NEWID()) R
ORDER BY
   id

APPLY, SQL Server 2005 ve
üstüdür

1
@bernd_k: evet, ancak 2011'de SQL Server 2000 kullanıcılarını yoksaymak gerçekçi olmalı ...
gbn
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.