2010-08-20 72 views
9

经过一番搜索和阅读文档之后,很明显,您可以在SQL Server中编写用户定义的函数,这些函数被标记为确定性或非确定性,具体取决于哪些内置函数是在身体内使用。在SQL Server中使用RAND创建非确定性函数

RAND()列在非确定性函数下(请参阅msdn article)。那么为什么我不能在一个函数中使用它?

回答

13

因为它有副作用。

函数中不允许带有副作用的构造。它具有的副作用是改变一些内部状态,以跟踪最后发出的rand()值。

我认为你可以通过将它包含在视图定义中然后从视图中选择来解决它。

+0

啊,现在我明白了!我没有想到最后一个随机数的内部存储。我可以看到这是如何区别于其他非确定性功能的。谢谢! – BG100 2010-08-20 14:24:34

+0

查看http://sqlfascination.com/tag/randomstring/它告诉你如何做到这一点。 – baash05 2012-04-12 00:25:52

19

使用视图可能适合您。因为,你已经发现了,一个UDF不能使用rand()函数,因为这将使该函数非determistic
Returning Random Numbers from a select statement

CREATE VIEW vRandNumber 
AS 
SELECT RAND() as RandNumber 

的观点是必要的。您可以通过使用View来诱骗UDF接受一个随机数。

CREATE FUNCTION RandNumber() 
RETURNS float 
AS 
    BEGIN 
    RETURN (SELECT RandNumber FROM vRandNumber) 
    END 

最后,您可以使用此功能在任何SELECT到现在0和1之间每行返回一个随机数:

SELECT dbo.RandNumber(), * 
FROM Northwind..Customers 
+4

+1查看技巧。我只记得这一点。这不是因为确定性。函数中允许'getdate()'。很明显,那个函数不能用于需要确定性函数的地方,例如持久计算列。这是因为副作用。引发的错误是“在函数中无效使用副作用运算符'rand'。” – 2010-08-20 13:59:58

+0

谢谢!我曾经听说过这样做是为了处理NEWID()函数,但没有意识到它也可以用于RAND()。 – BG100 2010-08-20 14:22:29

3

,我发现这个solution不创建一个视图:

基本上是:

而不是

SET @R = Rand() 

使用

SET @R = ABS(CHECKSUM(PWDENCRYPT(N'')))/2147483647.0 

在我来说,我想了一些1到10之间:

ROUND(((10 - 1 -1) * (ABS(CHECKSUM(PWDENCRYPT(N'')))/2147483647.0) + 1), 0)) 

ROUND(((@max - @lower -1) * (ABS(CHECKSUM(PWDENCRYPT(N'')))/2147483647.0) + @lower), 0)) 

如果你想有一个完整的解释:Using (Or Simulating) Rand() In A T-Sql User-Defined Function