简化持久计算列的 T-SQL 用户函数
Streamlining T-SQL user function for persisted computed column
我正在尝试简化以下 T-SQL 用户函数,以便在我的 table 之一的持久计算列中使用。我知道我可以在其他方法中使用视图中的计算列,但是由于用户要求的各种原因,最好按此方式实现此列。
但是为了在计算机专栏中使用这个标量函数,我正在努力使其尽可能高效和流线。函数的某些部分带有以下 SELECT COUNT
语句
SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
我反复使用,我想知道是否有更好的方法来重组此功能以提高效率。我确实尝试过使用 CTE 来包装这个 select 语句,但不断地 运行 陷入语法问题并且已经放弃了那个想法。
ALTER FUNCTION [dbo].[fnAccountReadyByID_Test]
(@JunctID INT = Null,
@AccountID VARCHAR(20) = NULL)
RETURNS VARCHAR(10)
AS
BEGIN
DECLARE @FamilyAccountReady as varchar(10),
@TotalFamily as INT;
SET @TotalFamily = (SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL)
IF @TotalFamily = 1
SET @FamilyAccountReady = (SELECT AccountStatus
FROM dbo.ApplicationJunctionT
WHERE JunctionID = @JunctID)
ELSE
SET @FamilyAccountReady = (CASE
WHEN (SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
AND [AccountStatus] = '-') > 0
THEN '-'
WHEN (SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
AND [AccountStatus] = 'Frozen') > 0
THEN 'Frozen'
WHEN (SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
AND [AccountStatus] = 'Closed') > 0
THEN 'Closed'
WHEN (SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
AND [AccountStatus] = 'Tentative') > 0
THEN 'Tentative'
ELSE 'GRANT'
END)
-- Return the result of the function
RETURN UPPER(@FamilyAccountReady)
END
另外,网上看了多篇文章也没找到电脑栏是怎么触发的。更新记录上的任何字段时是否触发?还是仅在更新变量字段时触发?
在这种情况下,我使用 AccountID
和 JunctionID
作为变量,它们都是不会改变的静态字段。我的计算列在这种情况下是否仍然有效?
尽管我不喜欢效率低下,但除非这里的专家社区可以提出一些改进建议,否则我可能不得不采用这种设计!
非常感谢您的协助!
如果您想使用 CTE,请尝试这样的操作:
WITH CTE AS (
SELECT [AccountStatus]
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
)
SELECT @FamilyAccountReady = CASE
WHEN EXISTS (SELECT * FROM CTE WHERE [AccountStatus] = '-') THEN '-'
WHEN EXISTS (SELECT * FROM CTE WHERE [AccountStatus] = 'Frozen') THEN 'Frozen'
WHEN EXISTS (SELECT * FROM CTE WHERE [AccountStatus] = 'Closed') THEN 'Closed'
WHEN EXISTS (SELECT * FROM CTE WHERE [AccountStatus] = 'Tentative') THEN 'Tentative'
ELSE 'GRANT'
END
但是,我认为使用基于访问其他表的函数的计算列不是一个好主意:您会收到一条错误消息 "Computed column 'ColumnName' in table 'TableName' cannot be persisted because the column is non-deterministic."
我正在尝试简化以下 T-SQL 用户函数,以便在我的 table 之一的持久计算列中使用。我知道我可以在其他方法中使用视图中的计算列,但是由于用户要求的各种原因,最好按此方式实现此列。
但是为了在计算机专栏中使用这个标量函数,我正在努力使其尽可能高效和流线。函数的某些部分带有以下 SELECT COUNT
语句
SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
我反复使用,我想知道是否有更好的方法来重组此功能以提高效率。我确实尝试过使用 CTE 来包装这个 select 语句,但不断地 运行 陷入语法问题并且已经放弃了那个想法。
ALTER FUNCTION [dbo].[fnAccountReadyByID_Test]
(@JunctID INT = Null,
@AccountID VARCHAR(20) = NULL)
RETURNS VARCHAR(10)
AS
BEGIN
DECLARE @FamilyAccountReady as varchar(10),
@TotalFamily as INT;
SET @TotalFamily = (SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL)
IF @TotalFamily = 1
SET @FamilyAccountReady = (SELECT AccountStatus
FROM dbo.ApplicationJunctionT
WHERE JunctionID = @JunctID)
ELSE
SET @FamilyAccountReady = (CASE
WHEN (SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
AND [AccountStatus] = '-') > 0
THEN '-'
WHEN (SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
AND [AccountStatus] = 'Frozen') > 0
THEN 'Frozen'
WHEN (SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
AND [AccountStatus] = 'Closed') > 0
THEN 'Closed'
WHEN (SELECT COUNT([JunctionID])
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
AND [AccountStatus] = 'Tentative') > 0
THEN 'Tentative'
ELSE 'GRANT'
END)
-- Return the result of the function
RETURN UPPER(@FamilyAccountReady)
END
另外,网上看了多篇文章也没找到电脑栏是怎么触发的。更新记录上的任何字段时是否触发?还是仅在更新变量字段时触发?
在这种情况下,我使用 AccountID
和 JunctionID
作为变量,它们都是不会改变的静态字段。我的计算列在这种情况下是否仍然有效?
尽管我不喜欢效率低下,但除非这里的专家社区可以提出一些改进建议,否则我可能不得不采用这种设计!
非常感谢您的协助!
如果您想使用 CTE,请尝试这样的操作:
WITH CTE AS (
SELECT [AccountStatus]
FROM dbo.ApplicationJunctionT
WHERE [AccountID] = @AccountID
AND [Outcome] IS NULL
AND [Change Account Status] IS NULL
)
SELECT @FamilyAccountReady = CASE
WHEN EXISTS (SELECT * FROM CTE WHERE [AccountStatus] = '-') THEN '-'
WHEN EXISTS (SELECT * FROM CTE WHERE [AccountStatus] = 'Frozen') THEN 'Frozen'
WHEN EXISTS (SELECT * FROM CTE WHERE [AccountStatus] = 'Closed') THEN 'Closed'
WHEN EXISTS (SELECT * FROM CTE WHERE [AccountStatus] = 'Tentative') THEN 'Tentative'
ELSE 'GRANT'
END
但是,我认为使用基于访问其他表的函数的计算列不是一个好主意:您会收到一条错误消息 "Computed column 'ColumnName' in table 'TableName' cannot be persisted because the column is non-deterministic."