我正在尝试学习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'
但是当我从触发器调用它时,它无法从存储过程返回一个值:
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是将此项目标记为非活动状态的应用程序用户的名称,它是我用来检查项目是否已设置为非活动状态而不是仅为此目的创建其他布尔列的方法。
我确定它的内容很简单,但有关If ... Then语句的信息似乎有限,很多答案建议使用Case但是查询编辑器会给我错误的语法错误我试图以这种方式做到这一点。
在我学习的过程中,如果我所做的是错误或糟糕的设计,我会非常高兴有人向我展示一种全新的处理方法。我希望创建一组触发器,将项目添加到任务表中,以便管理员检查用户帐户何时显示为陈旧和其他维护检查等。
我正在使用SQL Server 2005。
谢谢。
修改:已更改'值<>空'到'值不为空' Edit2:添加了HABO的建议,如果检测到多行,则抛出错误。
答案 0 :(得分:4)
我们如何对此采取全新方法。像这样的过程正是创建内联表值函数的原因。
让我们首先将存储过程转换为内联表值函数。
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行,它将正常工作。