在MS SQL Server 2005中使用RAND()时,我在做什么错?
我正在尝试从一张小桌子中随机选择10%的样本。我以为我只是使用RAND()函数,然后选择那些随机数小于0.10的行:
SELECT * FROM SomeTable WHERE SomeColumn='SomeCondition' AND RAND() < 0.10
但是我很快发现RAND()总是返回相同的数字!让我想起了这个xkcd卡通。
好的,没问题,RAND函数采用种子值。我将定期运行此查询,如果我在不同的日期运行它,我希望它给出不同的结果,因此我将日期和唯一行ID的组合作为种子:
SELECT * FROM SomeTable WHERE SomeColumn='SomeCondition' AND RAND(CAST(GETDATE) AS INTEGER) + RowID) < 0.10
我仍然没有任何结果!当我显示RAND返回的随机数时,我发现它们都在狭窄的范围内。看来从RAND获得随机数需要我们使用随机种子。如果我首先拥有一个随机种子,那么我就不需要一个随机数!
我已经看过与该问题有关的先前讨论:
SQL Server随机排序
如何在SQL中请求随机行?
他们没有帮助我。 TABLESAMPLE在页面级别工作,这对于一个大表而言非常有用,但对于一个小表而言却不是,并且看起来像它在WHERE子句之前适用。使用NEWID的TOP不起作用,因为我不提前知道要多少行。
有人有解决方案,或者至少有提示吗?
编辑:感谢AlexCuse提供了适用于我的特殊情况的解决方案。现在到更大的问题,如何使RAND表现出来?
解决方案
如果表中有一列(甚至是rowid列)在一般意义上是数字,例如整数,浮点数或者SQL数字,请尝试以下操作:
SELECT * FROM SomeTable WHERE SomeColumn='SomeCondition' AND 0*rowid+RAND() < 0.10
为了对每一行评估一次RAND(),而不是在查询开始时评估一次。
查询优化器是罪魁祸首。也许还有另一种方法,但是我相信这对我们有用。
这种方法(用表示)将不能保证10%的采样率。它只会给我们所有将Rand()评估为<.10的行,这将是不一致的。
就像是
select top 10 percent * from MyTable order by NEWID()
会成功的
编辑:并没有真正使RAND行为的好方法。这是我过去使用过的(提示警告它杀死了我们无法在UDF中使用Rand())
CREATE VIEW RandView AS SELECT RAND() AS Val GO CREATE FUNCTION RandomFloat() RETURNS FLOAT AS BEGIN RETURN (SELECT Val FROM RandView) END
然后,在查询中只需"从表中选择blah,dbo.RandomFloat()"。
你看到这个问题了吗?
如何在SQL Server 2005中将随机数作为列返回?
亚当发布了可以代替Rand()使用的UDF,它的效果要好得多。
这似乎可行:
select * from SomeTable where rand(0*SomeTableID + cast(cast(newid() as binary(4)) as int)) <= 0.10