在用户定义的函数中使用RAND()

use*_*912 8 sql-server sql-server-2012

我正在尝试创建一个用户定义的函数来调用其中的系统RAND()函数,当我尝试使用以下消息创建它错误的函数时:

消息443,级别16,状态1,过程getNumber,行10
在函数内无效使用副作用运算符'rand'.

我的功能代码:

CREATE FUNCTION getNumber(@_id int)
RETURNS DECIMAL(18,4)
AS
BEGIN
   DECLARE @RtnValue DECIMAL(18,4);

   SELECT TOP 1 @RtnValue = EmployeeID 
   FROM dbo.Employees
   ORDER BY EmployeeID DESC

   SET @RtnValue = RAND() * @RtnValue * (1/100)

   RETURN @RtnValue;
END
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

M.A*_*Ali 13

问题是您无法从用户定义的函数内部调用非确定性函数.

我通过创建一个视图来解决这个限制,在视图中调用该函数并在函数中使用该视图,类似这样......

查看定义

CREATE VIEW vw_getRANDValue
AS
SELECT RAND() AS Value
Run Code Online (Sandbox Code Playgroud)

功能定义

ALTER FUNCTION getNumber(@_id int )
RETURNS DECIMAL(18,4)
AS
BEGIN
   DECLARE @RtnValue DECIMAL(18,4);
   SELECT TOP 1 @RtnValue = EmployeeID 
   FROM dbo.Employees
   ORDER BY EmployeeID DESC

   SET @RtnValue = (SELECT Value FROM vw_getRANDValue) * @RtnValue * (1.0000/100.0000) --<-- to make sure its not converted to int
    RETURN @RtnValue;
END
Run Code Online (Sandbox Code Playgroud)

  • 我刚发布了一个你可能应该看看的答案.它涉及对此RAND视图的多次调用... (2认同)

Eny*_*yby 7

只需从外部将 RAND() 值作为参数传递:

CREATE FUNCTION getNumber(@_id int, @RAND FLOAT)
RETURNS DECIMAL(18,4)
AS
BEGIN
   DECLARE @RtnValue DECIMAL(18,4);

   SELECT TOP 1 @RtnValue = EmployeeID 
   FROM dbo.Employees
   ORDER BY EmployeeID DESC

   SET @RtnValue = @RAND * @RtnValue * (1/100)

   RETURN @RtnValue;
END
Run Code Online (Sandbox Code Playgroud)

并称为 getNumber(10, RAND())

没有任何副作用。


Shn*_*ugo 6

小心兰德!

如果你检查这个,你会看到,对这个VIEW的多次调用都返回了相同的值.这与NEWID()不同.因此,如果你真的想要随机数字,最好采取NEWID()并做一些"技巧"来获取一个数字 - 让我们说 - 第一个字节......

CREATE VIEW vw_getRANDValue
AS
SELECT RAND() AS Value
GO
CREATE VIEW vw_getNEWID
AS
SELECT NEWID() AS Value
GO
CREATE FUNCTION dbo.Test() 
RETURNS TABLE AS
RETURN
WITH Numbers AS
(SELECT 1 AS x UNION SELECT 2 UNION SELECT 3) 
SELECT *
     ,(SELECT Value FROM vw_getRANDValue) AS myRandom
     ,(SELECT Value FROM vw_getNEWID) AS myNewid
FROM Numbers
GO
SELECT * FROM dbo.Test();
GO
DROP FUNCTION dbo.Test;
GO
DROP VIEW vw_getRANDValue;
GO
DROP VIEW  vw_getNEWID;
GO      
Run Code Online (Sandbox Code Playgroud)

这是一个结果:

  1. 0,684530884058892 D1809581-BBD1-4D23-A7F9-BC697E869BB0
  2. 0,684530884058892 A4BAECDE-E993-46C1-B571-7440A713C371
  3. 0,684530884058892 D7A1CB65-D2BC-41B2-990D-C3BC52B056A2

随机BIGINT的视图可能如下所示:

CREATE VIEW vw_getRandomBigInt
AS
SELECT CONVERT(BIGINT,CONVERT(VARBINARY(16),NEWID(),1)) * (-1) AS Value
GO
Run Code Online (Sandbox Code Playgroud)

提示:我用很多行检查过它,看起来(只是通过视觉),这种方法并不是真正随机的(所有BIGINT都有相同的宽度......).这似乎工作正常:

CREATE VIEW vw_getRandomInt
AS
SELECT sys.fn_replvarbintoint(sys.fn_cdc_hexstrtobin(LEFT(REPLACE(CONVERT(VARCHAR(100),NEWID()),'-',''),4))) AS Value
GO
Run Code Online (Sandbox Code Playgroud)