Bitte schauen Sie sich diesen Code an:
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');
Nun, wann immer Sie dies ausführen
select *,
( select top 1 val from #t1 order by NEWID()) rnd
from #t1 order by 1;
Sie erhalten ein Ergebnis, bei dem alle Zeilen den gleichen Zufallswert haben. z.B
id val rnd
----------- ---------- ----------
1 a b
2 b b
3 c b
4 d b
Ich kenne eine Möglichkeit, mit einem Cursor die Zeilen zu schleifen und verschiedene Zufallswerte zu erhalten, aber das ist nicht performant.
Eine clevere Lösung dafür ist
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
Aber ich habe die Abfrage vereinfacht. Die eigentliche Abfrage sieht eher so aus
select *,
( select top 1 val from t2 where t2.x <> t1.y order by NEWID()) rnd
from t1 order by 1;
und die einfache Lösung passt nicht. Ich suche nach einer Möglichkeit, eine wiederholte Bewertung von zu erzwingen
( select top 1 val from #t1 order by NEWID()) rnd
ohne die Verwendung von Cursorn.
Bearbeiten: Gewünschte Ausgabe:
vielleicht 1 Anruf
id val rnd
----------- ---------- ----------
1 a c
2 b c
3 c b
4 d a
und ein zweiter Anruf
id val rnd
----------- ---------- ----------
1 a a
2 b d
3 c d
4 d b
Der Wert für jede Zeile sollte nur ein zufälliger Wert sein, der von den anderen Zeilen unabhängig ist
Hier ist die Cursorversion des Codes:
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
quelle
Antworten:
Eine Unterabfrage wird nach Möglichkeit einmal ausgewertet. Ich kann mich nicht erinnern, wie das "Feature" heißt (Falten?).
Gleiches gilt für die Funktionen GETDATE und RAND. NEWID wird zeilenweise ausgewertet, da es sich um einen zufälligen Wert handelt und niemals denselben Wert zweimal generieren sollte.
Die üblichen Techniken sind die Verwendung von NEWID als Eingabe für CHECKSUM oder als Startwert für RAND
Für zufällige Werte pro Zeile:
Wenn Sie eine zufällige Reihenfolge wünschen:
Wenn Sie eine zufällige Reihenfolge mit einer Zeilenreihenfolge wünschen. Die Reihenfolge von ActualOrder bleibt hier unabhängig von der Reihenfolge der Ergebnismenge erhalten
Bearbeiten:
In diesem Fall können wir die Anforderung wie folgt angeben:
Dies unterscheidet sich von dem, was ich oben angeboten habe, bei dem Zeilen einfach auf verschiedene Arten neu angeordnet werden
Also würde ich CROSS APPLY in Betracht ziehen. Die WHERE-Klausel erzwingt eine zeilenweise Auswertung und vermeidet das Problem des "Faltens" und stellt sicher, dass val und rnd immer unterschiedlich sind. CROSS APPLY kann auch recht gut skaliert werden
quelle