3

我正在尝试从一张小桌子中随机选择 10% 的样本。我以为我会使用 RAND() 函数并选择随机数小于 0.10 的那些行:

SELECT * FROM SomeTable
WHERE SomeColumn='SomeCondition' AND
      RAND() < 0.10

但我很快发现 RAND() 总是返回相同的数字!让我想起了这部xkcd 卡通

OK,没问题,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 提供适用于我的特殊情况的解决方案。现在到更大的问题,如何让兰德表现?

4

5 回答 5

6

这种类型的方法(由 ΤZΩΤZΙΟΥ 显示)不能保证 10% 的采样。它只会为您提供所有 Rand() 被评估为 < .10 的行,这将是不一致的。

就像是

select top 10 percent * from MyTable order by NEWID()

会成功的。

编辑:没有真正让兰德表现的好方法。这是我过去使用的(kludge alert - 它会杀死你无法在 UDF 中使用 Rand())

CREATE VIEW RandView AS 

SELECT RAND() AS Val

GO

CREATE FUNCTION RandomFloat()
RETURNS FLOAT
AS
BEGIN

RETURN (SELECT Val FROM RandView)

END

然后你就select blah, dbo.RandomFloat() from table在你的查询中。

于 2008-10-02T18:28:51.807 回答
2

如果您的表有一列(甚至可能是rowid列)是一般意义上的数字,如整数、浮点或 SQL 数字,请尝试以下操作:

SELECT * FROM SomeTable WHERE SomeColumn='SomeCondition' AND 0*rowid+RAND() < 0.10

为了对每一行RAND()计算一次,而不是在查询开始时计算一次。

查询优化器是罪魁祸首。也许还有另一种方法,但我相信这对你有用。

于 2008-10-02T17:43:18.080 回答
1

这似乎有效:

select * from SomeTable
where rand(0*SomeTableID + cast(cast(newid() as binary(4)) as int)) <= 0.10
于 2008-10-02T19:45:21.797 回答
0

你看到这个问题了吗?

如何在 SQL Server 2005 中将随机数作为列返回?

Adam 发布了一个 UDF,您可以使用它来代替 Rand() 效果更好。

于 2008-10-02T19:43:30.677 回答
0

这似乎有效

SELECT TOP 10 PERCENT * FROM schema.MyTable ORDER BY NEWID()
于 2011-01-26T15:00:55.300 回答