You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何向表值函数传入REPLICATE(NEWID())时,NEWID会被重复计算?

问题:表值函数传入REPLICATE(NEWID(),2)时出现异常结果

我编写了如下dbo.chunk表值函数,用于将字符串按指定长度拆分,测试时发现两种调用方式结果不一致:

函数代码

CREATE FUNCTION dbo.chunk(@input VARCHAR(MAX), @chunkSize INT = 36)
RETURNS TABLE AS    
RETURN (
    WITH CTE AS (
        SELECT SUBSTRING(@input,1,@chunkSize) AS [chunk], 1 AS [row]
        UNION ALL
        SELECT SUBSTRING(@input,1+([row]*@chunkSize),@chunkSize)
        , [row] + 1 
        FROM cte
        WHERE LEN(@input) > ([row]*@chunkSize)  
    )
    SELECT [chunk] 
    FROM cte
)
GO

测试代码

/* 以下执行结果符合预期 */
DECLARE @input varchar(MAX) = REPLICATE(NEWID(),2);
SELECT * FROM dbo.chunk(@input,36)

/* 但以下执行结果异常,REPLICATE调用了两次NEWID() */
SELECT * FROM dbo.chunk(REPLICATE(NEWID(),2),36);

测试结果

第一种调用方式(传变量)结果:

chunk
E1810B3D-3DD4-4F55-B650-ED2DB28BCF70
E1810B3D-3DD4-4F55-B650-ED2DB28BCF70

第二种调用方式(直接传表达式)结果:

chunk
89A26C8B-D5C7-47A8-BBBC-FE859B24E267
F9636F76-1ED6-4D19-A309-BA35EAC9F782

原因解释

核心问题出在SQL Server对非确定性函数的求值逻辑上:

  • NEWID()属于非确定性函数,这类函数每次被调用时都会生成新的结果,不会复用之前的值。
  • 第一种调用方式中,REPLICATE(NEWID(),2)先赋值给变量@input,此时NEWID()仅执行一次,变量存储了两个相同GUID拼接的固定字符串。函数递归拆分时,所有引用都是基于这个固定字符串,所以两个chunk内容一致。
  • 第二种调用方式中,REPLICATE(NEWID(),2)直接作为参数传入函数。由于函数内部的递归CTE会在锚点查询和递归查询中两次引用@input参数,每次引用都会重新计算这个表达式,导致NEWID()被执行两次,生成两个不同的GUID,最终两个chunk内容不同。

简单来说,非确定性函数作为参数直接传入递归表值函数时,会随着函数内部的多次引用被反复求值,从而出现不符合预期的结果。

内容的提问来源于stack exchange,提问作者user19463405

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 16:55:16