用户定义函数 (TSQL) 非确定性和计算持久列
user defined function (TSQL) non deterministic and computed persisted column
我有一个 table,在它的列中有两列 INT
类型,它们被称为:
ExpirationMonth
和
ExpirationYear
我想向这个 table 添加一个新列,其值将根据 ExpirationMonth
和 ExpirationYear
的值计算。因此,此列将是一个计算列。
为此,我创建了一个用户定义的标量函数,它根据 ExpirationMonth
和 ExpirationYear
的值计算此列的值。函数的定义如下:
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
我收到以下错误:
Computed column 'IsExpired' in table 'Table_Name' cannot be persisted
because the column is non-deterministic.
我从上面的语句中删除了 PERSISTED
并再次 运行 。然后我注意到该列已添加了预期值。
我的问题是,如果可能的话,我怎样才能让这个专栏持久化?
我意识到这个错误的原因是在IsExpired
函数中使用了GETDATE
函数。由于 GETDATE
不是确定性的,因此 IsExpired
也不是确定性的。
但是,我不明白我们如何才能使这个函数 IsExpired
具有确定性,并因此将计算列定义为持久化列(如果可能的话)。
你能告诉我这是否可行吗?如果可行,我该怎么做。
该值是不确定的,因为它取决于当前日期。您不能保留其值会随时间变化的计算列。
有关确定性函数的详细信息,请参阅 MSDN 上的 this article。
我建议在视图中进行
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
我有一个 table,在它的列中有两列 INT
类型,它们被称为:
ExpirationMonth
和
ExpirationYear
我想向这个 table 添加一个新列,其值将根据 ExpirationMonth
和 ExpirationYear
的值计算。因此,此列将是一个计算列。
为此,我创建了一个用户定义的标量函数,它根据 ExpirationMonth
和 ExpirationYear
的值计算此列的值。函数的定义如下:
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
我收到以下错误:
Computed column 'IsExpired' in table 'Table_Name' cannot be persisted because the column is non-deterministic.
我从上面的语句中删除了 PERSISTED
并再次 运行 。然后我注意到该列已添加了预期值。
我的问题是,如果可能的话,我怎样才能让这个专栏持久化?
我意识到这个错误的原因是在IsExpired
函数中使用了GETDATE
函数。由于 GETDATE
不是确定性的,因此 IsExpired
也不是确定性的。
但是,我不明白我们如何才能使这个函数 IsExpired
具有确定性,并因此将计算列定义为持久化列(如果可能的话)。
你能告诉我这是否可行吗?如果可行,我该怎么做。
该值是不确定的,因为它取决于当前日期。您不能保留其值会随时间变化的计算列。
有关确定性函数的详细信息,请参阅 MSDN 上的 this article。
我建议在视图中进行
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