首页 > 解决方案 > SQL Server - 来自 DATETIME 的 DATE 转换是不确定的,但仅在用户定义的函数中

问题描述

为什么在 SQL Server 的用户定义函数 (UDF) 的返回表中,这种类型转换会因为计算列的不确定性而被拒绝?PERSISTED

CREATE FUNCTION MyTimeIntervalFunction(@Param1 INT)
RETURNS @MyTimeInterval TABLE
(
     StartUtc   DATETIME    NOT NULL PRIMARY KEY
    ,EndUtc     DATETIME    NOT NULL
    ,DateUtc    AS CONVERT(DATE, StartUtc) PERSISTED
)
AS BEGIN
    --do stuff
    RETURN
END

在此处输入图像描述

请注意,这不是转换字符串表示或字符串表示转换,所以我不知道为什么它不起作用,因为全球化/区域的东西应该是无关紧要的。

这适用于UDF(包括存储过程)之外:

DECLARE @MyTimeInterval TABLE
(
     StartUtc   DATETIME    NOT NULL PRIMARY KEY
    ,EndUtc     DATETIME    NOT NULL
    ,DateUtc    AS CONVERT(DATE, StartUtc) PERSISTED
)
INSERT INTO @MyTimeInterval(StartUtc, EndUtc)
VALUES ('2018-01-01', '2018-01-02')
SELECT * FROM @MyTimeInterval

在此处输入图像描述

似乎添加WITH SCHEMABINDING到 UDF 定义会关闭它,但我不明白为什么,因为它看起来只是将函数输出标记为基于输入参数的确定性。而且我必须在我的函数中做其他非确定性的事情 ,所以它不是一个候选的解决方法。

不稳定的字符串操作也可能是一种解决方法,但不是可取的。CONVERT根据 SQL Server ,ISO-8601 的样式 126仍然是不确定的。似乎唯一的选择是放弃使用持久计算列?

标签: sql-serverdatetimecalculated-columnsnon-deterministicpersisted-column

解决方案


正如在这个有点相关的答案开头所提到的,不指定WITH SCHEMABINDING意味着 SQL Server 会跳过对确定性和数据访问等内容的检查。

由于PERSISTED在计算机列中要求“计算列表达式”是确定性的,并且 SQL Server 会跳过任何检查它是否实际上是确定性的,因此不允许这样做。即使您有像i AS 1 PERSISTED.

(这与函数本身的所有内容是否都是确定性的无关。)

综上所述,据我所知,在 TVF 中使用PERSISTED实际上并没有为函数添加任何内容。


推荐阅读