我可以使 SQL Server FORMAT 具有确定性吗?

Posted

技术标签:

【中文标题】我可以使 SQL Server FORMAT 具有确定性吗?【英文标题】:Can I make SQL Server FORMAT deterministic? 【发布时间】:2016-06-03 18:46:25 【问题描述】:

我想制作一个返回整数形式的 UDF YYYYMM,这样我就可以轻松地在月份划分一些东西。我正在尝试将此函数分配给 PERSISTED 计算列的值。

我目前有以下,效果很好:

CREATE FUNCTION dbo.GetYearMonth(@pDate DATETIME2)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
    DECLARE @fYear VARCHAR(4) = RIGHT('0000' + CAST(YEAR(@pDate) AS VARCHAR),4)
    DECLARE @fMonth VARCHAR(2) = RIGHT('00' + CAST(MONTH(@pDate) AS VARCHAR),2)

    RETURN CAST(@fYear + @fMonth AS INT)
END

但我认为改用FORMAT 会更干净。我试过这个:

CREATE FUNCTION dbo.GetYearMonth(@pDate DATETIME2)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
    DECLARE @fYear VARCHAR(4) = FORMAT(@pDate,'yyyy', 'en-us')
    DECLARE @fMonth VARCHAR(2) = FORMAT(@pDate,'MM', 'en-us')

    RETURN CAST(@fYear + @fMonth AS INT)
END

但是这个函数是不确定的。 有没有办法使FORMAT 具有确定性?还是有更好的方法来做到这一点,使 UDF 具有确定性?

【问题讨论】:

你要为计算列使用函数吗? @FLICKER 是的,我是。一个持久的。 请看我的回答。我也不知道你为什么使用 SCEHMEBINDING @FLICKER schemabinding 必须有任何机会被认为是确定性的。 嗯,我不知道,反正我认为使用 convert 也是确定性的 【参考方案1】:

有趣的问题,所以我做了一些挖掘,但没有得出任何结论:)

以Deterministic and Nondeterministic Functions开头

没有明确列出FORMAT,但声明:

所有聚合和字符串内置函数都是确定性的。

以及指向String Functions的链接

同样,此页面声明

所有内置字符串函数都是确定性的。这意味着在使用一组特定的输入值调用它们时,它们会返回相同的值。

但是,the page on FORMAT 对此保持沉默。

FORMAT 使用 doesn't preclude it from being deterministic 的 CLR,但 doco 对 FORMAT 的实际实现保持沉默。

最后,怀疑这是 doco(或代码)中的错误,quick search of connect 什么也没显示。

测试用例怎么样? (欢迎评论此代码的有效性……)

CREATE FUNCTION WhatAmI(@Number INTEGER) 
RETURNS NVARCHAR
WITH SCHEMABINDING
AS 
BEGIN
RETURN FORMAT(@Number, 'd')
END
GO

SELECT OBJECTPROPERTY(OBJECT_ID('WhatAmI'),'IsDeterministic')

-----------
0

(1 row(s) affected)

Nup,这是不确定的。

所以,一个有趣的练习,但没有结论。

那么我们学到了什么(根据 BOL)?如果内置函数是不确定的,那么就没有办法做到这一点。有些都取决于参数类型,有些应该是但不是。

【讨论】:

请vote on fixing this bug。【参考方案2】:

我想知道你为什么要使用函数。 您可以使用一个简单的公式:

CONVERT(varchar(6), getdate(), 112) 

【讨论】:

因为我不知道我能做到这一点 这条评论给了我想要的东西,但没有具体回答这个问题,所以我投了赞成票,但没有接受。 +1。具体来说,样式 112 (ISO) 是确定性的。根据docs,有些样式是确定性的,有些则不是。【参考方案3】:

Microsoft 对格式函数能否具有确定性并不是很清楚。我在其文档中找不到有关该主题的任何信息。作为一个 CLR 函数,我猜 awnser 是不可能的。

按照您想要的方式格式化整数的更简单的解决方案是:

YEAR(@pDate) * 100 + MONTH(@pDate)

【讨论】:

这条评论给了我想要的东西,但没有具体回答这个问题,所以我投了赞成票,但没有接受。

以上是关于我可以使 SQL Server FORMAT 具有确定性吗?的主要内容,如果未能解决你的问题,请参考以下文章

Access 和 SQL Server 计算日期不同

SQL Server 2005 事务日志条目:LOP_Format_Page

SQL SERVER FORMAT函数 日期格式化

SQL Server:如何将float格式化为字符串,不使用逗号?

有啥方法可以创建与 SQL Server 2005 中的视图具有相同布局的表?

不一样的 SQL Server 日期格式化