2011-12-14 114 views
15

我在一个表中有触发器,并且想要在插入,更新或删除行时读取UserId值。怎么做?下面的代码不工作,我对UPDATEDSQL Server:触发如何读取插入,更新,删除的值

ALTER TRIGGER [dbo].[UpdateUserCreditsLeft] 
    ON [dbo].[Order] 
    AFTER INSERT,UPDATE,DELETE 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    DECLARE 
    @UserId INT, 

    SELECT @UserId = INSERTED.UserId FROM INSERTED, DELETED 

    UPDATE dbo.[User] SET CreditsLeft = CreditsLeft - 1 WHERE Id = @UserId 
END 
+4

它也*错误,因为这些表中可能有多行,所以试图读取一个值到一个变量会给你那些行的值之一(哪一个是未定义的)。 – 2011-12-14 14:21:20

+1

除了编写一个认为只有一行将被改变的三角架,这是一个糟糕的做法,您已经使用了隐式连接,这也是一个sql反模式。永远不要使用隐含的连接。现在你有一个你可能不想要的交叉连接。在将隐式连接替换为更好的显式连接之后将近20年编写此类代码是不可原谅的。 – HLGEM 2011-12-14 16:28:06

回答

24

请注意,inserted, deleted的含义与inserted CROSS JOIN deleted相同,并给出每一行的每个组合。我怀疑这是你想要的。

像这样的东西可以帮助你开始...

SELECT 
    CASE WHEN inserted.primaryKey IS NULL THEN 'This is a delete' 
     WHEN deleted.primaryKey IS NULL THEN 'This is an insert' 
             ELSE 'This is an update' 
    END as Action, 
    * 
FROM 
    inserted 
FULL OUTER JOIN 
    deleted 
    ON inserted.primaryKey = deleted.primaryKey 


取决于你想做什么,你再引用表,你有兴趣与inserted.userIDdeleted.userID等。


最后,要注意inserteddeleted并且可以(和确实)包含多个记录。

如果一次插入10条记录,inserted表将包含所有10条记录。这同样适用于删除表和deleted表。并且在更新的情况下都是这两个表。


编辑 Examplee触发后OP的编辑。

ALTER TRIGGER [dbo].[UpdateUserCreditsLeft] 
    ON [dbo].[Order] 
    AFTER INSERT,UPDATE,DELETE 
AS 
BEGIN 

    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    UPDATE 
    User 
    SET 
    CreditsLeft = CASE WHEN inserted.UserID IS NULL THEN <new value for a DELETE> 
         WHEN deleted.UserID IS NULL THEN <new value for an INSERT> 
                ELSE <new value for an UPDATE> 
        END 
    FROM 
    User 
    INNER JOIN 
    (
     inserted 
    FULL OUTER JOIN 
     deleted 
     ON inserted.UserID = deleted.UserID -- This assumes UserID is the PK on UpdateUserCreditsLeft 
    ) 
     ON User.UserID = COALESCE(inserted.UserID, deleted.UserID) 

END 


如果UpdateUserCreditsLeft的PrimaryKey的比用户名以外的东西,使用的FULL OUTER JOIN代替。

20

得到错误没有updated动态表。只有inserteddeleted。在UPDATE命令中,旧数据存储在deleted动态表中,新值存储在inserted动态表中。

UPDATE想象成DELETE/INSERT组合。

+0

我已将行更改为SELECT @UserId = UserId FROM INSERTED,DELETED,现在我得到错误列名'UserId'。 – Tomas 2011-12-14 14:22:43

-4

下面是创建触发器的语法:

CREATE TRIGGER trigger_name 
ON { table | view } 
[ WITH ENCRYPTION ] 
{ 
    { { FOR | AFTER | INSTEAD OF } { [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] } 
     [ WITH APPEND ] 
     [ NOT FOR REPLICATION ] 
     AS 
     [ { IF UPDATE (column) 
      [ { AND | OR } UPDATE (column) ] 
       [ ...n ] 
     | IF (COLUMNS_UPDATED () { bitwise_operator } updated_bitmask) 
       { comparison_operator } column_bitmask [ ...n ] 
     } ] 
     sql_statement [ ...n ] 
    } 
} 

如果您想要使用的更新,你只能用IF UPDATE (column)部分做到这一点。这是不可能做你所问的。