在MS SQL Server 2005中使用RAND()时,我在做什么错?

时间:2020-03-06 15:02:23  来源:igfitidea点击:

我正在尝试从一张小桌子中随机选择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