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'行?!
如果是这样..呃.. :(这是否意味着我需要在这个触发器中使用光标?(如果我需要为每一行做一些独特的逻辑,我现在这样做).
?
我将添加完整的触发器代码,看看是否可以在没有光标的情况下完成它.
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)
为什么不更改触发器来处理多行?不需要游标或循环:这是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)