如何在 SQL 触发器中使用嵌套的 If 语句

How to use nested If statements in SQL trigger

我正在尝试学习 SQL 触发器来自动处理我数据库中的事件,但我在执行时遇到了一些问题。

如果我运行下面的代码:

declare @userid numeric(18,0);
declare @username nvarchar(max);
set @userid = 400
execute GetUserNameFromID @userid,@username output
select @username

调用以下存储过程:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE GetUserNameFromID 
    -- Add the parameters for the stored procedure here
    @UserID numeric(18,0),
    @UserName nvarchar(MAX) OUT
AS
BEGIN
    SET NOCOUNT ON;

    SELECT @UserName = u.name from Users u where ID=@UserID
END
GO

我得到了一个不错的结果'sometestuser'

但是当从我的触发器调用它时,它无法 return 来自存储过程的值:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Trigger [dbo].[CheckIfUserHasNoItemsLeft] on [dbo].[Items] for update
As

Begin
set nocount on 

declare @inactive_user nvarchar(50);
declare @userid numeric(18,0);
declare @username nvarchar(MAX);

if ( select Count(*) from inserted ) > 1 RaIsError( 'CheckIfIserHasNoItemsLeft: No more than one row may be processed.', 25, 42 ) with log

if update(InactiveUser)
    set @inactive_user = (select InactiveUser from inserted)
    if @inactive_user is not null
        set @userid = (select CID from inserted)
        execute GetuserNameFromID @userid,@username output
        if @username is not null        
            insert into tasks (Task) values ('The last item for ' + @username + ' has been marked inactive, check if this user should now be also marked inactive.')
End

InactiveUser 是将此项目标记为非活动的应用程序用户的名称,这是我用来检查该项目是否已设置为非活动的,而不是为此创建一个额外的布尔列。

我确定这很简单,但是有关 SQL 的 If...Then 语句的信息似乎是有限的,很多答案都建议使用 Case,但查询编辑器给我关于语法不正确的错误 否无论我尝试以哪种方式做到这一点。

在我学习的过程中,我非常高兴有人向我展示一种全新的处理方法,如果我所做的是错误的或糟糕的设计。我希望创建一组触发器,将项目添加到任务中 table 以便管理员检查用户帐户何时过时以及其他维护检查等

我正在使用 SQL 服务器 2005。

谢谢。

编辑:将 'value <> null' 更改为 'value is not null' Edit2:添加了 HABO 的建议,如果检测到多行则抛出错误。

要不我们采用一种全新的方法来解决这个问题。像这样的过程正是创建内联 table 值函数的原因。

让我们从将存储过程转换为内联 table 值函数开始。

CREATE FUNCTION GetUserNameFromID 
(
    @UserID numeric(18,0)
) RETURNS TABLE 
AS RETURN

    SELECT u.name 
    from Users u 
    where ID = @UserID
GO

这比带有输出变量的存储过程要简单和清晰得多。

这是它真正开始发挥作用的地方。以下是您可以使用新创建的 iTVF 对该触发器执行的操作。

ALTER Trigger [dbo].[CheckIfUserHasNoItemsLeft] on [dbo].[Items] for update
As Begin

set nocount on 

if update(InactiveUser)
    insert into tasks (Task) 
    select 'The last item for ' + u.name + ' has been marked inactive, check if this user should now be also marked inactive.'
    from inserted i
    cross apply dbo.GetUserNameFromID(i.CID) u
end

这非常简单,而且完全基于设置,因此如果您更新 1 行或 1,000 行,它将正常工作。