S'il vous plaît regarder ce code:
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');
Maintenant, chaque fois que vous exécutez cela
select *,
( select top 1 val from #t1 order by NEWID()) rnd
from #t1 order by 1;
vous obtiendrez un résultat avec où toutes les lignes ont la même valeur aléatoire. par exemple.
id val rnd
----------- ---------- ----------
1 a b
2 b b
3 c b
4 d b
Je connais un moyen d'utiliser un curseur pour boucle jeter les lignes et obtenir différentes valeurs aléatoires, mais ce n'est pas performant.
Une solution intelligente à ceci est
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
Mais j'ai simplifié la requête. La vraie requête ressemble plus à
select *,
( select top 1 val from t2 where t2.x <> t1.y order by NEWID()) rnd
from t1 order by 1;
et la solution simple ne convient pas. Je cherche un moyen de forcer une évaluation répétée de
( select top 1 val from #t1 order by NEWID()) rnd
sans l'utilisation de curseurs.
EDIT: Sortie souhaitée:
peut-être 1 appel
id val rnd
----------- ---------- ----------
1 a c
2 b c
3 c b
4 d a
et un deuxième appel
id val rnd
----------- ---------- ----------
1 a a
2 b d
3 c d
4 d b
La valeur de chaque ligne devrait juste être une valeur aléatoire indépendante des autres rangées
Voici la version du curseur du code:
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
Une sous-requête est évaluée une fois si possible. Je ne me souviens pas de ce qu'on appelle la "fonctionnalité" (pliante?) Désolé.
La même chose s'applique aux fonctions GetDate et Rand. NeufID est évalué une ligne à la ligne, car elle est intrinsèquement une valeur aléatoire et ne doit jamais générer la même valeur deux fois.
Les techniques habituelles sont à utiliser utilisez NeufID comme entrée de la somme de contrôle ou comme une graine à rand
Pour les valeurs aléatoires par ligne:
SELECT
co1l, col2,
ABS(CHECKSUM(NEWID())) AS Random1,
Rand(CHECKSUM(NEWID())) AS Random2
FROM
MyTable
Si vous voulez ordre aléatoire:
SELECT
co1l, col2
FROM
MyTable
ORDER BY
NEWID()
Si vous voulez un ordre aléatoire avec une commande de ligne aussi. Commander actuel ici est préservé quelle que soit l'ordre des Resultset
SELECT
id, val,
ROWNUMBER() OVER (ORDER BY id) AS id
FROM
#t1
ORDER BY
NEWID()
Éditer:
Dans ce cas, nous pouvons énoncer l'exigence comme suit:
- renvoyer toute valeur aléatoire du jeu pour chaque ligne de l'ensemble
- la valeur aléatoire sera différente de la valeur réelle de n'importe quelle ligne
Ceci est différent de ce que j'ai proposé ci-dessus, qui recommande simplement des lignes de différentes manières
Donc, je considérerais croix s'appliquer. La clause oblige la clause à l'évaluation par la ligne d'évaluation et évite le problème "pliable" et garantit que Val et RND sont toujours différents. Cross Appliquer peut aussi bien augmenter
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