【问题标题】:Computed Column cannot be Persisted计算列不能持久化
【发布时间】:2010-12-16 11:15:28
【问题描述】:

我有一个自定义函数,我正在尝试使用此函数创建一个持久列。

它给了我以下错误。

表“SomeTable”中的计算列“FormattedSSN”无法持久化,因为该列是不确定的。

函数如下:

ALTER FUNCTION [dbo].[FormatSSN]()
RETURNS VARCHAR(11)
AS
BEGIN
    return '';
END

这是使用函数添加列的查询:

ALTER TABLE SomeTable
ADD FormattedSSN as dbo.FormatSSN() PERSISTED

请建议是否有任何出路。谢谢。

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    像这样将 WITH SCHEMABINDING 添加到函数中:

    ALTER FUNCTION [dbo].[FormatSSN]
    (
    @SSN    VARCHAR(9)
    )
    RETURNS CHAR(11)
    WITH SCHEMABINDING
    AS
    BEGIN
      your stuff here
    END
    

    然后运行这个来验证:

    IF OBJECTPROPERTY (OBJECT_ID(N'[dbo].[FormatSSN]'),'IsDeterministic') = 1
       PRINT 'Function is detrministic.'
    ELSE IF OBJECTPROPERTY (OBJECT_ID(N'[dbo].[FormatSSN]'),'IsDeterministic') = 0
       PRINT 'Function is NOT detrministic'
    GO
    

    在这里工作。

    【讨论】:

    • 太棒了。但是这个函数与常规函数有什么不同(行为)?
    • 谢谢。我知道其他情况下的 SCHEMABINDING(例如视图)。看起来它在这里的工作方式几乎相同。对表的任何更改都会引发错误。
    【解决方案2】:

    直接指定定义怎么样:

    ALTER TABLE SomeTable
    ADD FormattedSSN as
        case when len(EmployeeSSN) = 9 then
                substring(EmployeeSSN, 1, 3) + '-' +
                substring(EmployeeSSN, 4, 2) + '-' +
                substring(EmployeeSSN, 6, 4)
        else EmployeeSSN end
    PERSISTED
    

    【讨论】:

    • 耶!...它工作:)...你能解释一下为什么吗?这个和我发的有什么区别?它是否会以同样的方式工作?
    • 引擎无法判断 UDF 可能有什么副作用,因为它可能会在以后修改,并且每次运行时都会重新计算它的缓存计划。将计算列表示为 SQL 表达式时,它知道没有不确定的副作用。
    【解决方案3】:

    不调用UDF,而是将计算列表达式设置为

    Case When Len(EmployeeSSN) = 0 Then 
          SUBSTRING(EmployeeSSN, 1, 3) + '-' + 
          SUBSTRING(EmployeeSSN, 4, 2) + '-' + 
          SUBSTRING(EmployeeSSN, 6, 4)
        Else EmployeeSSN End
    

    在创建表脚本中,您可以添加一列:

    [NewColumnName]  As
       (Case When len([UpdateUserId])=(0) T
             Then (((substring([UpdateUserId],(1),(3))+'-')+
                     substring([UpdateUserId],(4),(2)))+'-')+
                     substring([UpdateUserId],(6),(4)) 
             Else [UpdateUserId] End) PERSISTED,
    

    【讨论】:

      【解决方案4】:

      创建适当数据类型的非计算列。创建一个插入触发器(如果数据将更改,则创建一个更新触发器)。然后,您可以将函数输出保存在列中。

      ALTER TABLE SomeTable ADD FormattedSSN VARCHAR(11)
      GO
      
      CREATE TRIGGER dbo.TR_I_SomeTable ON  dbo.SomeTable AFTER INSERT
      AS 
      BEGIN
          SET NOCOUNT ON;
      
          update s
          set s.FormattedSSN = dbo.FormatSSN()
          from SomeTable AS s
              join inserted i on i.id = s.id
      
      END
      GO
      

      【讨论】:

      • 这非常适合非确定性函数,例如FORMAT。谢谢!
      猜你喜欢
      • 2012-12-16
      • 2010-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多