ber*_*d_k 11 sql-server-2005 sql-server
请看这段代码:
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');
Run Code Online (Sandbox Code Playgroud)
现在,每当你执行这个
select *,
( select top 1 val from #t1 order by NEWID()) rnd
from #t1 order by 1;
Run Code Online (Sandbox Code Playgroud)
您将得到一个结果,其中所有行都具有相同的随机值。例如
id val rnd
----------- ---------- ----------
1 a b
2 b b
3 c b
4 d b
Run Code Online (Sandbox Code Playgroud)
我知道一种使用游标循环抛出行并获得不同随机值的方法,但这不是高效的。
一个聪明的解决方案是
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
Run Code Online (Sandbox Code Playgroud)
但我简化了查询。真正的查询看起来更像
select *,
( select top 1 val from t2 where t2.x <> t1.y order by NEWID()) rnd
from t1 order by 1;
Run Code Online (Sandbox Code Playgroud)
简单的解决方案不适合。我正在寻找一种方法来强制重复评估
( select top 1 val from #t1 order by NEWID()) rnd
Run Code Online (Sandbox Code Playgroud)
不使用游标。
编辑:想要的输出:
也许 1 个电话
id val rnd
----------- ---------- ----------
1 a c
2 b c
3 c b
4 d a
Run Code Online (Sandbox Code Playgroud)
和第二个电话
id val rnd
----------- ---------- ----------
1 a a
2 b d
3 c d
4 d b
Run Code Online (Sandbox Code Playgroud)
每行的值应该是一个独立于其他行的随机值
这是代码的光标版本:
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
Run Code Online (Sandbox Code Playgroud)
gbn*_*gbn 11
如果可能,子查询会被评估一次。我不记得“功能”叫什么(折叠?)抱歉。
这同样适用于 GETDATE 和 RAND 函数。NEWID 是逐行计算的,因为它本质上是一个随机值,不应两次生成相同的值。
通常的技术是使用 NEWID 作为 CHECKSUM 的输入或 RAND 的种子
对于每行的随机值:
SELECT
co1l, col2,
ABS(CHECKSUM(NEWID())) AS Random1,
RAND(CHECKSUM(NEWID())) AS Random2
FROM
MyTable
Run Code Online (Sandbox Code Playgroud)
如果你想要随机顺序:
SELECT
co1l, col2
FROM
MyTable
ORDER BY
NEWID()
Run Code Online (Sandbox Code Playgroud)
如果您也想要随机顺序和行顺序。无论结果集的顺序如何,这里都会保留 ActualOrder 顺序
SELECT
id, val,
ROWNUMBER() OVER (ORDER BY id) AS id
FROM
#t1
ORDER BY
NEWID()
Run Code Online (Sandbox Code Playgroud)
编辑:
在这种情况下,我们可以将需求表述为:
- 为集合中的每一行返回集合中的任何随机值
- 随机值将与任何行中的实际值不同
这与我上面提供的不同,它只是以各种方式重新排序行
所以,我会考虑交叉申请。WHERE 子句强制逐行评估并避免“折叠”问题并确保 val 和 rnd 始终不同。CROSS APPLY 也可以很好地扩展
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
Run Code Online (Sandbox Code Playgroud)