【问题标题】:SQL : can't get IDENTITY value in TriggerSQL:无法在触发器中获取 IDENTITY 值
【发布时间】: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。

请告诉我该怎么做?

提前致谢。

【问题讨论】:

    标签: sql sql-server triggers


    【解决方案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 请您评论一下,使用插入语句的输出子句捕获标识值是个好主意还是坏主意
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-08
      • 1970-01-01
      • 2011-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多