SQL:无法在触发器中获取 IDENTITY 值

Posted

技术标签:

【中文标题】SQL:无法在触发器中获取 IDENTITY 值【英文标题】:SQL : can't get IDENTITY value in Trigger 【发布时间】:2010-12-16 05:52:17 【问题描述】:

我是 SQL 新手。我正在创建一个虚拟项目。在我的项目中,我有一个注册页面,我想创建一个用户名(名字 + 姓氏 + 用户 ID)。但问题是,我无法捕获用户 ID value.I 已经使用了 After Trigger 和而不是 Trigeer。下面是我的脚本 -

表-

CREATE TABLE UserInfo
(
    UserID INT IDENTITY(1,1),
    FirstName NVARCHAR(500),
    LastName NVARCHAR(500),
    [Password] NVARCHAR(200),
    EmailID NVARCHAR(200),
    [Address] NVARCHAR(500),
    CountryID INT,
    StateID INT,
    UserName NVARCHAR(500)
)

插入数据的过程 -

CREATE PROC Create_User    
 @FirstName NVARCHAR(500),    
 @LastName NVARCHAR(500),    
 @Password NVARCHAR(200),    
 @EmailID NVARCHAR(200),    
 @Address NVARCHAR(500),    
 @CountryID INT,    
 @StateID INT,    
 @UserID INT OUTPUT    
AS    
 BEGIN    
 INSERT INTO UserInfo (FirstName,LastName,[Password],EmailID,[Address],CountryID,StateID)    
 VALUES    
 (@FirstName,@LastName,@Password,@EmailID,@Address,@CountryID,@StateID)    

 SET @UserID = SCOPE_IDENTITY();    

 END 

触发后-

CREATE TRIGGER Create_UserName
ON UserInfo
AFTER INSERT
AS
BEGIN
DECLARE @_UName VARCHAR(200);
SET @_UName = (SELECT FirstName+LastName+Cast(UserID AS NVARCHAR(100)) from INSERTED )

INSERT INTO UserInfo (UserName) VALUES (@_UName)
END
    GO

输出 - 插入两行

而不是触发器 -

CREATE TRIGGER Create_UserName
ON UserInfo
INSTEAD OF INSERT
AS
BEGIN
DECLARE @UName NVARCHAR(200);
DECLARE @FName NVARCHAR(200);
DECLARE @LName NVARCHAR(200);
DECLARE @UPassword NVARCHAR(200);
DECLARE @UEmailID NVARCHAR(200);
DECLARE @UAddress NVARCHAR(200);
DECLARE @UCountryID INT;
DECLARE @UStateID INT;
SET @UName = (SELECT FirstName+LastName+Cast(UserID AS NVARCHAR(100)) from INSERTED )
SET @FName = (SELECT FirstName from INSERTED )
SET @LName = (SELECT LastName from INSERTED )
SET @UPassword = (SELECT [Password] from INSERTED )
SET @UEmailID = (SELECT EmailID from INSERTED )
SET @UAddress = (SELECT [Address] from INSERTED )
SET @UCountryID = (SELECT CountryID from INSERTED )
SET @UStateID = (SELECT StateID from INSERTED )




INSERT INTO UserInfo (FirstName,LastName,[Password],EmailID,[Address],CountryID,StateID,UserName)  
VALUES (@FName,@LName,@UPassword,@UEmailID,@UAddress,@UCountryID,@UStateID,@UName)
END
    GO

输出 - 这工作正常,但身份为 0。

请告诉我该怎么做?

提前致谢。

【问题讨论】:

【参考方案1】:

你有问题

为什么你有一个存储过程而不是 INSTEAD OF?使用存储过程或代替触发器:不能同时使用 其次,触发器仅针对一行进行编码 after 触发器是插入新行,应该是更新

至于为什么:

存储过程没有 INSERT 来捕获 IDENTITY 值:INSERT 的范围实际上是触发器而不是触发器。如果您切换到@@IDENTITY(不好的做法),您会从 AFTER 触发器中获得 IDENTITY 值。

做什么:

删除两个触发器:它们没有任何价值

如果无法更改用户名,则向表中添加计算列

例如

ALTER TABLE UserInfo ADD UserName AS FirstName+LastName+Cast(UserID AS NVARCHAR(100)
...或者向存储的过程中添加 UPDATE 用户名可以稍后更改

例如

CREATE PROC Create_User    
...
AS    

SET NOCOUNT, XACT_ABORT ON

BEGIN TRY
 BEGIN TRAN

 INSERT INTO UserInfo
   (FirstName,LastName,[Password],EmailID,[Address],CountryID,StateID)    
 VALUES    
   (@FirstName,@LastName,@Password,@EmailID,@Address,@CountryID,@StateID)

 SET @UserID = SCOPE_IDENTITY();    

 UPDATE UserInfo
 SET UserName = @FirstName+@LastName+Cast@UserID AS NVARCHAR(100)
 WHERE UserID = @UserID

   COMMIT TRAN
END TRY
BEGIN CATCH
   IF XACT_STATE() <> 0 ROLLBACK TRAN
END CATCH
GO

【讨论】:

【参考方案2】:

试试这个触发器:

CREATE TRIGGER Create_UserName
ON UserInfo
AFTER INSERT
AS
BEGIN
    --DECLARE @_UName VARCHAR(500), @user_id INT
    --SELECT @_UName = FirstName + LastName + Cast(UserID AS NVARCHAR(100)), @user_id = UserId FROM INSERTED

    UPDATE UserInfo 
    SET UserName = i.FirstName + i.LastName + Cast(i.UserID AS NVARCHAR(100))
    FROM UserInfo u
    INNER JOIN Inserted I ON (i.UserId = u.UserId)
    --WHERE   UserId = @user_id
END

【讨论】:

是的,该代码应该可以正常工作! :-)(顺便说一句:是的,我知道原始代码直接来自原始帖子) 除了 INSTEAD OF 触发器是单行并且不会解决问题 感谢@gbn 我也想到了这一点,因为每个行操作都会引发触发器(离开我从未使用过的 INSTEAD OF)但必须做一些工作,所以修改了代码。 为每批行而不是每一行触发一个触发器。您永远不应该假设触发器只会在一行上起作用。【参考方案3】:

如果您有 SQL-Server 2005+,您可以使用插入语句的输出子句。

CREATE PROC Create_User    
 @FirstName NVARCHAR(500),    
 @LastName NVARCHAR(500),    
 @Password NVARCHAR(200),    
 @EmailID NVARCHAR(200),    
 @Address NVARCHAR(500),    
 @CountryID INT,    
 @StateID INT,    
 @UserID INT OUTPUT    
AS    
 BEGIN
    DECLARE @OV Table (id int);

    INSERT INTO UserInfo (FirstName,LastName,[Password],EmailID,[Address],CountryID,StateID)
    inserted.id into @OV  
    VALUES (@FirstName,@LastName,@Password,@EmailID,@Address,@CountryID,@StateID)    

    SELECT @UserID = id FROM @OV;    
    update UserInfo set UserName = FirstName + LastName + Cast(UserID AS NVARCHAR) where UserID  = @userid
END 

编辑:添加了缺少的关键字,更新了用户名列

【讨论】:

我编辑了代码。顺便说一句,这是我现在要实施的模式,因为我不再需要支持 SQL 2000。 更新用户名列和插入的两行怎么样? @gbn 谢谢我忽略了用户名的更新。但我仍然不明白你所说的插入两行是什么意思 @bernd_k:AFTER 触发器插入第二行:OP 在中间声明它 @gbn 请您评论一下,使用插入语句的输出子句捕获标识值是个好主意还是坏主意

以上是关于SQL:无法在触发器中获取 IDENTITY 值的主要内容,如果未能解决你的问题,请参考以下文章

而不是 SQL Server 中的触发器丢失 SCOPE_IDENTITY?

而不是SQL Server中的触发器丢失SCOPE_IDENTITY?

SQL关键字汇总

当 IDENTITY_INSERT 设置为 OFF 时,SQL 无法在表“表”中插入标识列的显式值 [重复]

如何在触发器中获取sql语句

SQL而不是触发器有时不会触发?