我有以下触发器,但由于trigger needs to handle multiple records,我不知道如何在我的触发器代码中正确处理它。
有人可以建议我如何更改下面的TSql以正确处理多条记录,而不只是一条记录(如下面列出的那样)。
CREATE TABLE [dbo].[tblArticle](
[IdArticle] [int] IDENTITY(1,1) NOT NULL,
[IdArticleStatus] [tinyint] NOT NULL,
[Title] [nvarchar](200) NOT NULL,
[CleanTitle] [nvarchar](300) NOT NULL,
[UniqueTitle] [nvarchar](300) NOT NULL,
[Content] [nvarchar](max) NOT NULL
GO
ALTER TABLE [dbo].[tblArticle] ADD CONSTRAINT [DF_tblArticle_CleanTitle]
DEFAULT (newid()) FOR [CleanTitle]
GO
ALTER TABLE [dbo].[tblArticle] ADD CONSTRAINT [DF_tblArticle_UniqueTitle]
DEFAULT (newid()) FOR [UniqueTitle]
GO
ALTER TRIGGER [dbo].[ArticlesAfterInsertOrUpdate]
ON [dbo].[tblArticle]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON
DECLARE @IdArticle INTEGER,
@Title NVARCHAR(300),
@CleanTitle NVARCHAR(300),
@UniqueTitle NVARCHAR(300),
@NewCleanTitle NVARCHAR(300),
@CleanTitleCount INTEGER
-- Only Update the CleanTitle and UniqueTitle if *required*
-- This means, create a unique subject of the title, then check if this clean value
-- is different to the current clean value. If so, then update both clean and unique.
-- Otherwise, don't do anything (because it will include this row in the count check, below).
IF UPDATE(Title) BEGIN
-- TODO: How will this handle multiple records???
SELECT @IdArticle = IdArticle, @Title = Title, @CleanTitle = CleanTitle
FROM INSERTED
-- Create the 'Slugs'.
SET @NewCleanTitle = dbo.CreateUniqueSubject(@Title)
SET @UniqueTitle = @NewCleanTitle
IF @NewCleanTitle != @CleanTitle BEGIN
-- We need to update the clean and unique, so lets get started...
-- Grab the count :: eg. how many other _clean_ titles already exist?
-- Note: this is the _only_ reason why we have this
-- column - because it has an index on it.
SELECT @CleanTitleCount = COUNT(IdArticle)
FROM [dbo].[tblArticle]
WHERE CleanTitle = @NewCleanTitle
-- If we have some previous titles, then we need to append a number
-- to the end of the current slug.
IF @CleanTitleCount > 0
SET @UniqueTitle = @NewCleanTitle + CAST((@CleanTitleCount + 1) AS VARCHAR(10))
-- Now update the unique subject field.
UPDATE [dbo].[tblArticle]
SET CleanTitle = @NewCleanTitle,
UniqueTitle = @UniqueTitle
WHERE IdArticle = @IdArticle
END
END
END
GO
请帮忙!
答案 0 :(得分:1)
不需要知道自定义函数的作用,只是它为每个给定的输入(即标题)返回相同的值。在触发器中执行这种类型的逻辑会有点复杂,但你当然可以实现它。肯定还有其他方法可以让它工作,最好的方法完全取决于你的环境,但是下面的逻辑会让你得到你想要的东西作为起点:
ALTER TRIGGER [dbo].[ArticlesAfterInsertOrUpdate]
ON [dbo].[tblArticle]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON
-- Only Update the CleanTitle and UniqueTitle if *required*
-- This means, create a unique subject of the title, then check if this clean value
-- is different to the current clean value. If so, then update both clean and unique.
-- Otherwise, don't do anything (because it will include this row in the count check, below).
IF UPDATE(Title) BEGIN
-- Materialize with the newCleanTitle value for simplicity sake, could
-- do this inline below, not sure which would work better in your environment
if object_id('tempdb..#tempIData') > 0
drop table #tempIData;
select *,
dbo.CreateUniqueSubject(i.Title) as newCleanTitle
into #tempIData
from inserted i
where i.CleanTitle <> dbo.CreateUniqueSubject(i.Title);
with iData as
( -- Get the data inserted along with a running tally of any duplicate
-- newCleanTitle values
select i.IdArticle as IdArticle,
i.CleanTitle, i.newCleanTitle,
-- Need to get the count here as well to account for cases where
-- we insert multiple records with the same resulting cleanTitle
cast(row_number() over(partition by i.newCleanTitle order by i.IdArticle) as bigint) as cntCleanTitle
from #tempIData i
),
srcData as
( -- Get the existing count of data by CleanTitle value for each
-- newCleanTitle included in the inserted data
select t.CleanTitle as CleanTitle,
cast(coalesce(count(*),0) as bigint) as cntCleanTitle
from dbo.tblArticle t
join
( -- Need a distinct list of newCleanTitle values
select a.newCleanTitle
from iData a
group by a.newCleanTitle
) i
-- Join on CleanTitle as we need to get the existing running
-- count for each distinct CleanTitle values
on t.CleanTitle = i.newCleanTitle
group by t.CleanTitle
)
-- Do the update...
update a
set a.CleanTitle = i.newCleanTitle,
a.UniqueTitle =
case
when i.cntCleanTitle + coalesce(s.cntCleanTitle,0) > 1
then i.newCleanTitle + cast((cast(i.cntCleanTitle as bigint) + cast(coalesce(s.cntCleanTitle,0) as bigint)) as nvarchar(10))
else
i.newCleanTitle
end
from dbo.tblArticle a
join iData i
on a.IdArticle = i.IdArticle
left join srcData s
on i.newCleanTitle = s.CleanTitle;
if object_id('tempdb..#tempIData') > 0
drop table #tempIData;
END
END