views:

253

answers:

3

I have function which I am using in one of the SQL Job (see function below). I am trying to created a persisted column on this function based on existing column on the same table.

It is giving me following error.

Computed column 'FormattedSSN' in table 'SomeTable' cannot be persisted because the column is non-deterministic.

Please suggest if there is any way out. Thanks.

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[FormatSSN]
(
@SSN    VARCHAR(9)
)
RETURNS CHAR(11)
AS
BEGIN
    Declare @FormattedSSN char(11);
    IF(LEN(@SSN) = 9)
    BEGIN
         set @FormattedSSN = SUBSTRING(@SSN, 1, 3) + '-' + SUBSTRING(@SSN, 4, 2) + '-' + SUBSTRING(@SSN, 6,4) 
    END
    ELSE
    BEGIN
      set @FormattedSSN = @SSN
    END

return @FormattedSSN;

END

EDIT: Query used below

ALTER TABLE SomeTable
ADD FormattedSSN as dbo.FormatSSN([EmployeeSSN]) PERSISTED
+2  A: 

How about specifying the definition directly:

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
schinazi
Yay!...it worked :)...Can you explain why? Whats the difference between this and the one I posted? Whether it gonna work same way?
noob.spt
The engine cannot tell what side effects the UDF might have, as it could be modified later, and the cached plan for it is recomputed each time it is run. When representing the computed column as a SQL expression, it knows there are no non-deterministic side effects.
Charles Bretana
Thanks Charles.
noob.spt
+1  A: 

Instead of calling the UDF, Set the computed column expression to

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

In the Create Table script you can add a column:

[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,
Charles Bretana
+2  A: 

Add WITH SCHEMABINDING like this:

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

and then run this to verify:

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

Works here.

Damir Sudarevic
Awesome. But how is this function different(behavior) from regular function?
noob.spt
Thanks. I knew about SCHEMABINDING in other contexts (e.g. views). It seems it will work pretty much same here. Any change to table will throw an error.
noob.spt