Sql server 如何处理此Sql Server触发器中的多行?
我有下面的触发器,但因为,我不确定如何正确处理它,在我的触发器代码中 有人可以建议我如何更改下面的TSql以正确处理多个记录,而不是下面列出的单个记录 表模式和默认值。 触发器,它只处理一条记录。。。不是多重的。Sql server 如何处理此Sql Server触发器中的多行?,sql-server,sql-server-2008,triggers,Sql Server,Sql Server 2008,Triggers,我有下面的触发器,但因为,我不确定如何正确处理它,在我的触发器代码中 有人可以建议我如何更改下面的TSql以正确处理多个记录,而不是下面列出的单个记录 表模式和默认值。 触发器,它只处理一条记录。。。不是多重的。 请帮忙 实际上不需要知道自定义函数的作用,只需要它为每个给定的输入(即标题)返回相同的值即可。在触发器中执行这种类型的逻辑有点复杂,但您肯定可以实现它。当然,还有其他方法可以让它工作,最好的方法完全取决于您的环境,但是以下逻辑将为您提供您想要的起点: ALTER TRIGGER [db
请帮忙 实际上不需要知道自定义函数的作用,只需要它为每个给定的输入(即标题)返回相同的值即可。在触发器中执行这种类型的逻辑有点复杂,但您肯定可以实现它。当然,还有其他方法可以让它工作,最好的方法完全取决于您的环境,但是以下逻辑将为您提供您想要的起点:
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
您已经正确地确定触发器需要能够处理多行。因此,重新编写TSQL来实现这一点。我看不出这里有什么问题。@Mitch Wheat:这正是我的问题:我不确定如何:附加到CleanTitle以使UniqueTitle连续的值是否重要?需要更多信息:函数CreateUniqueSubject做什么?自定义函数只接受一个nvarcharmax,用自定义delimeter替换“坏字符”,并返回nvarcharmax结果。这是为了删除任何无效的URI字符。
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
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