用户定义的函数(TSQL)非确定性和计算的持久列

时间:2015-04-21 15:33:08

标签: sql sql-server tsql udf persisted-column

我有一个表格,在其列的列中有两列INT类型,它们被称为:

ExpirationMonth

ExpirationYear

我想在此表中添加一个新列,其值将根据ExpirationMonthExpirationYear的值进行计算。所以这个列将是一个计算列。

为此,我创建了一个用户定义的标量函数,该函数根据ExpirationMonthExpirationYear的值计算此列的值。该功能的定义如下:

CREATE FUNCTION [dbo].[IsExpired]
(
    @ExpirationMonth INT,
    @ExpirationYear INT
)
RETURNS BIT
AS
BEGIN
    DECLARE @Today DATE = GETDATE()
    DECLARE @PreviousMonth INT = MONTH(@today)-1
    DECLARE @CurrentYear INT = YEAR(@today)

    DECLARE @IsExpired BIT = 0

    IF(@ExpirationYear<@CurrentYear OR
      (@ExpirationYear=@CurrentYear AND @ExpirationMonth<=@PreviousMonth))
        SET @IsExpired = 1

    RETURN @IsExpired

END

最初,我尝试按以下方式添加列:

ALTER Table_Name
ADD IsExpired AS [dbo].[IsExpired]([ExpirationMonth], [ExpirationYear]) PERSISTED

我收到以下错误:

  

计算专栏&#39; IsExpired&#39;在表格&#39; Table_Name&#39;不能坚持下去   因为该列是非确定性的。

我从上面的语句中删除了PERSISTED,然后再次运行它。然后我注意到该列已添加了预期值。

我的问题是,如果可以的话,我怎样才能保留此列?

我意识到这个错误的原因是在GETDATE函数中使用了IsExpired函数。由于GETDATE不具有确定性,IsExpired不具有确定性。

但是,我不知道如何使这个函数IsExpired成为确定性的,并且因此将计算列定义为持久化(如果可能的话)。

请您告诉我这是否可能,如果可能,我该怎么办呢。

2 个答案:

答案 0 :(得分:2)

该值是不确定的,因为它取决于当前日期。您不能保留其值可能随时间变化的计算列。

有关确定性函数的详细信息,请参阅MSDN上的this article

答案 1 :(得分:0)

我建议在视图中进行操作

SELECT * INTO yourTable
FROM (VALUES(2015,1),(2015,2),(2015,3),(2015,4),(2015,5),(2015,6)) AS A(ExpirationYear,ExpirationMonth);
GO

CREATE VIEW vw_Expiration
AS
SELECT  ExpirationYear,
        ExpirationMonth,
        CASE
            WHEN    ExpirationYear < YEAR(GETDATE()) OR
                    (ExpirationYear = YEAR(GETDATE()) AND ExpirationMonth <= MONTH(GETDATE()))
                THEN 1
            ELSE 0
        END AS IsExpired
FROM yourTable;
GO

SELECT *
FROM vw_Expiration

结果:

ExpirationYear ExpirationMonth IsExpired
-------------- --------------- -----------
2015           1               1
2015           2               1
2015           3               1
2015           4               1
2015           5               0
2015           6               0