【问题标题】:Cannot persist computed column - not deterministic无法持久化计算列 - 不确定
【发布时间】:2012-12-16 23:04:07
【问题描述】:

我有一个计算列的函数:

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]))

还有列定义:

[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 没关系使用它。但真的没有什么比我刚才说的更多了。

【问题讨论】:

  • 问题不在于您的函数,而在于您表上的计算列。在您的问题上发布该定义,以便我们为您提供帮助
  • 这适用于什么版本的 SQL-Server?
  • 你改了哪一行?您的意思是您将计算列定义更改为直接使用RETURN dateadd(...)
  • @AndriyM 是的,正如 damien 建议的那样,我取出了原始转换并用更明确的版本替换它。
  • 看起来 SQL Fiddle 存在问题。 this 工作得更好吗? sqlfiddle.com/#!6/8fd88/1/0

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


【解决方案1】:

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) 代替它。这样做后,函数本身就变得确定了

【讨论】:

  • 如果在 SQL-Server 2012 上,他们还可以使用 - 而不是 CONVERT([varchar](4),@Year,(0))+'-01-01' - DATEFROMPARTS([Year],1,1) 函数:SQL-Fiddle test
  • 您好,我尝试更换零件,但遇到了另一个问题:/请参阅上面的编辑。
猜你喜欢
  • 2010-12-16
  • 2019-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多