当我在表中执行INSERT时出现奇怪的触发器问题

Pur*_*ome 1 sql t-sql sql-server triggers sql-server-2008

我有一个附加在桌子上的触发器.

ALTER TRIGGER [dbo].[UpdateUniqueSubjectAfterInsertUpdate]
   ON  [dbo].[Contents]
   AFTER INSERT,UPDATE
AS
BEGIN

-- Grab the Id of the row just inserted/updated
DECLARE @Id INT

SELECT @Id = Id
FROM INSERTED

END
Run Code Online (Sandbox Code Playgroud)

每次插入或修改新条目时,我希望更新单个字段(在此表中).为了这个问题,想象一下我正在更新LastModifiedOn(datetime)字段.

好的,所以我得到的是批量插入东西..

INSERT INTO [dbo].[Contents]
SELECT Id, a, b, c, d, YouDontKnowMe
FROM [dbo].[CrapTable]
Run Code Online (Sandbox Code Playgroud)

现在所有行都被正确插入.LastModifiedOn字段默认为null.因此,所有条目都为null - 除了第一行.

这是否意味着没有为插入表中的每一行调用触发器,但是一旦插入查询完成后,即.是否插入了所有行?这意味着,INSERTED表(在触发器中)没有一行,但是'n'行?!

如果是这样..呃.. :(这是否意味着我需要在这个触发器中使用光标?(如果我需要为每一行做一些独特的逻辑,我现在这样做).

UPDATE

我将添加完整的触发器代码,看看是否可以在没有光标的情况下完成它.

BEGIN
    SET NOCOUNT ON

    DECLARE @ContentId INTEGER,
        @ContentTypeId TINYINT,
        @UniqueSubject NVARCHAR(200),
        @NumberFound INTEGER

    -- Grab the Id. Also, convert the subject to a (first pass, untested)
    -- unique subject.
    -- NOTE: ToUriCleanText just replaces bad uri chars with a ''. 
    --   eg. an '#' -> ''
    SELECT @ContentId = ContentId, @ContentTypeId = ContentTypeId, 
        @UniqueSubject = [dbo].[ToUriCleanText]([Subject])
    FROM INSERTED

    -- Find out how many items we have, for these two keys.
    SELECT @NumberFound = COUNT(ContentId)
    FROM [dbo].[Contents]
    WHERE ContentId = @ContentId
        AND UniqueSubject = @UniqueSubject

    -- If we have at least one identical subject, then we need to make it 
    -- unique by appending the current found number.
    -- Eg. The first instance has no number. 
    --     Second instance has subject + '1',
    --     Third instance has subject + '2', etc...
    IF @NumberFound > 0
        SET @UniqueSubject = @UniqueSubject + CAST(@NumberFound AS NVARCHAR(10))

    -- Now save this change.
    UPDATE [dbo].[Contents]
    SET UniqueSubject = @UniqueSubject
    WHERE ContentId = @ContentId
END
Run Code Online (Sandbox Code Playgroud)

gbn*_*gbn 8

为什么不更改触发器来处理多行?不需要游标或循环:这是SQL的全部要点......

UPDATE
    dbo.SomeTable
SET
    LastModifiedOn = GETDATE()
WHERE
    EXIST (SELECT * FROM INSERTED I WHERE I.[ID] = dbo.SomeTable.[ID]
Run Code Online (Sandbox Code Playgroud)

编辑:像...的东西

INSERT @ATableVariable
    (ContentId, ContentTypeId, UniqueSubject)
SELECT 
    ContentId, ContentTypeId, [dbo].[ToUriCleanText]([Subject])
FROM
    INSERTED

UPDATE
    [dbo].[Contents]
SET
    UniqueSubject + CAST(NumberFound AS NVARCHAR(10))
FROM
    --Your original COUNT feels wrong and/or trivial
    --Do you expect 0, 1 or many rows.
    --Edit2: I assume 0 or 1 because of original WHERE so COUNT(*) will suffice
    -- .. although, this implies an EXISTS could be used but let's keep it closer to OP post
    (
    SELECT ContentId, UniqueSubject, COUNT(*) AS NumberFound
    FROM @ATableVariable
    GROUP BY ContentId, UniqueSubject
    HAVING COUNT(*) > 0
    ) foo
    JOIN
    [dbo].[Contents] C ON C.ContentId = foo.ContentId AND C.UniqueSubject = foo.UniqueSubject
Run Code Online (Sandbox Code Playgroud)

编辑2:再次使用RANKING

UPDATE
    C
SET
    UniqueSubject + CAST(foo.Ranking - 1 AS NVARCHAR(10))
FROM
    (
    SELECT
        ContentId, --not needed? UniqueSubject,
        ROW_NUMBER() OVER (PARTITION BY ContentId ORDER BY UniqueSubject) AS Ranking
    FROM
        @ATableVariable
    ) foo
JOIN
    dbo.Contents C ON C.ContentId = foo.ContentId 
    /* not needed? AND C.UniqueSubject = foo.UniqueSubject */
WHERE
foo.Ranking > 1
Run Code Online (Sandbox Code Playgroud)