我有一个计算列的函数:
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
从不介意使用它。但实际上只有我刚才所说的。
答案 0 :(得分:19)
CONVERT([varchar](4),@Year,(0))+'-01-01'
正在传递给DATEDIFF
调用,位于预期日期的位置,会强制进行隐式转换。
来自deterministic functions的规则:
CAST
确定性除非与
datetime
,smalldatetime
或sql_variant
一起使用。
CONVERT
确定性,除非存在以下条件之一:
...
源或目标类型为
datetime
或smalldatetime
,其他源或目标类型为字符串,并指定非确定性样式。要确定性,样式参数必须是常量。此外,小于或等于100的样式是不确定的,但样式20和21除外。大于100的样式是确定性的,样式106,107,109和113除外。
嗯,你没有打电话,但是你依赖于隐式转换,我希望它会像CAST
一样。我不是依赖于此,而是转而使用CONVERT
并给出确定的样式参数。
所以,我会这样做:CONVERT(datetime,CONVERT([varchar](4),@Year,(0))+'0101',112)
代替它。完成后,函数本身就变得具有确定性