如何在 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 行,它将正常工作。
我正在尝试学习 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 行,它将正常工作。