无法持久计算列 - 不确定

时间:2013-01-02 15:19:12

标签: sql-server database sql-server-2008-r2 calculated-columns

我有一个计算列的函数:

CREATE FUNCTION [dbo].[GetAllocatedStartTime](@Year INT, @Week INT)
RETURNS DATETIME

WITH schemabinding
AS BEGIN
    RETURN dateadd(week,@Week-(1),dateadd(day,(-1),dateadd(week,datediff(week,(0),CONVERT([varchar](4),@Year,(0))+'-01-01'),(1))))
END

GO

我添加了WITH schemabinding,希望它能确定它,所以我可以坚持下去。它应该是两个输入[Week][Year]将始终产生相同的结果。

确切的错误是:

  

表'Tmp_Bookings'中的计算列'AllocatedTimeStart'无法保留,因为该列是非确定性的。

我在列中使用此公式:

([dbo].[GetAllocatedStartTime]([Year],[Week]))

列defs:

[Week] [int] NOT NULL,
[Year] [int] NOT NULL,
[AllocatedTimeStart]  AS ([dbo].[GetAllocatedStartTime]([Year],[Week])),

有什么想法吗?

修改

将行改为:

RETURN dateadd(week,@Week-(1),dateadd(day,(-1),dateadd(week,datediff(week,(0),CONVERT(datetime,CONVERT([varchar](4),@Year,(0))+'0101',112)),(1))))

但是现在我收到错误,说该列的公式无效。即使该功能保存得很好。

编辑2:

我已经准确地展示了我在做什么(或至少我已经尝试过)。真的没什么。正如它所说的前一个函数(原始函数)加上公式ref [dbo].AllocatedStartDate(...)在列中工作,但没有持久,它说这是不确定的。所以根据建议,我更改了FUNCTION,用新代码替换了转换部分,所以现在的功能如下:

FUNCTION [dbo].[GetSTime](@Year INT, @Week INT)

RETURNS DATETIME
WITH schemabinding
AS BEGIN
    RETURN dateadd(week,@Week-(1),dateadd(day,(-1),dateadd(week,datediff(week,(0),CONVERT(datetime,CONVERT([varchar](4),@Year,(0))+'0101',112)),(1))))
END

然后我在计算字段(([dbo].[GetAllocatedStartTime]([Year],[Week])))中尝试了与之前相同的公式...并且它拒绝了公式,说它无效......这很奇怪,因为公式是相同的,所以它必须是对变化的函数进行某种检查并发现它是无效的,这也很奇怪,因为我做了一个简单的SELECT dbo.GetAllocatedStartTime(2012,13)并且它有效...

所以是的我很困惑,我从未见过SqlFiddle从不介意使用它。但实际上只有我刚才所说的。

1 个答案:

答案 0 :(得分:19)

CONVERT([varchar](4),@Year,(0))+'-01-01'正在传递给DATEDIFF调用,位于预期日期的位置,会强制进行隐式转换。

来自deterministic functions的规则:

  

CAST

     

确定性除非与datetimesmalldatetimesql_variant一起使用。

     

CONVERT

     

确定性,除非存在以下条件之一:

     

...

     

源或目标类型为datetimesmalldatetime,其他源或目标类型为字符串,并指定非确定性样式。要确定性,样式参数必须是常量。此外,小于或等于100的样式是不确定的,但样式20和21除外。大于100的样式是确定性的,样式106,107,109和113除外。

嗯,你没有打电话,但是你依赖于隐式转换,我希望它会像CAST一样。我不是依赖于此,而是转而使用CONVERT并给出确定的样式参数。

所以,我会这样做:CONVERT(datetime,CONVERT([varchar](4),@Year,(0))+'0101',112)代替它。完成后,函数本身就变得具有确定性