我在SQL Server 2012中的表上有以下触发器:
CREATE TRIGGER [dbo].[UpdateTotals]
ON [dbo].[DEC10assessmentData]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--update list pract test 1 total
if update (list_practTest1_s1) or update (list_practTest1_s2)
begin
update DEC10assessmentData
set list_practTest1_total = CAST(list_practTest1_s1 AS decimal(3 , 1)) + CAST(list_practTest1_s2 AS decimal(3 , 1))
where
TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_practTest1_s1) IS NOT NULL
and TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_practTest1_s2) IS NOT NULL
update DEC10assessmentData
set list_practTest1_total = NULL
where
TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_practTest1_s1) IS NULL
or TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_practTest1_s2) IS NULL
end
--update list test 1 total
if UPDATE (list_test1_s1) or update (list_test1_s2)
begin
update DEC10assessmentData
set list_test1_total = CAST(list_test1_s1 AS decimal(3 , 1)) + CAST(list_test1_s2 AS decimal(3 , 1))
where
TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_test1_s1) IS NOT NULL
and TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_test1_s2) IS NOT NULL
update DEC10assessmentData
set list_test1_total = NULL
where
TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_test1_s1) IS NULL
or TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_test1_s2) IS NULL
end
--update list pract test 2 total
if update (list_practTest2_s1) or update (list_practTest2_s2)
begin
update DEC10assessmentData
set list_practTest2_total = CAST(list_practTest2_s1 AS decimal(3 , 1)) + CAST(list_practTest2_s2 AS decimal(3 , 1))
where
TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_practTest2_s1) IS NOT NULL
and TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_practTest2_s2) IS NOT NULL
update DEC10assessmentData
set list_practTest2_total = NULL
where
TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_practTest2_s1) IS NULL
or TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_practTest2_s2) IS NULL
end
--update list test 2 total
if UPDATE (list_test2_s1) or update (list_test2_s2)
begin
update DEC10assessmentData
set list_test2_total = CAST(list_test2_s1 AS decimal(3 , 1)) + CAST(list_test2_s2 AS decimal(3 , 1))
where
TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_test2_s1) IS NOT NULL
and TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_test2_s2) IS NOT NULL
update DEC10assessmentData
set list_test2_total = NULL
where
TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_test2_s1) IS NULL
or TRY_CONVERT(decimal(3 , 1) , dbo.DEC10assessmentData.list_test2_s2) IS NULL
end
--update read total
update DEC10assessmentData
set read_total = ((read_test1_Scaled / 100 * 8) + (read_test2_scaled / 100 * 12)) / 20 * 100
where
read_test1_Scaled is not null and read_test2_scaled is not null
--update read total to null where scores don't exist
update DEC10assessmentData
set read_total = NULL
where
read_test1_Scaled is null or read_test2_scaled is null
--update write total
update DEC10assessmentData
set writ_total = (CAST(writ_literatureReview as decimal(3,1)) / 100 * 4
+ CAST(writ_exposition as decimal(3,1)) / 100 * 8
+ CAST(writ_groupReport as decimal(3,1)) / 100 * 8
+ cast(writ_synthSummary as decimal(3,1)) / 100 * 8
+ cast(writ_critEvaluation as decimal(3,1)) / 100 * 12) / 40 * 100
where
TRY_CONVERT(decimal(3 , 1) , writ_literatureReview) is not null and
TRY_CONVERT(decimal(3 , 1) , writ_exposition) is not null and
TRY_CONVERT(decimal(3 , 1) , writ_groupReport) is not null and
TRY_CONVERT(decimal(3 , 1) , writ_synthSummary) is not null and
TRY_CONVERT(decimal(3 , 1) , writ_critEvaluation) is not null
--update write total where scores don't exist
update DEC10assessmentData
set writ_total = NULL
where
TRY_CONVERT(decimal(3 , 1) , writ_literatureReview) is null or
TRY_CONVERT(decimal(3 , 1) , writ_exposition) is null or
TRY_CONVERT(decimal(3 , 1) , writ_groupReport) is null or
TRY_CONVERT(decimal(3 , 1) , writ_synthSummary) is null or
TRY_CONVERT(decimal(3 , 1) , writ_critEvaluation) is null
--update list total
update DEC10assessmentData
set list_total = ((list_test1_scaled / 100 * 8) + (list_test2_scaled / 100 * 12)) / 20 * 100
where
list_test1_scaled is not null and list_test2_scaled is not null
--update list total to null where scores don't exist
update DEC10assessmentData
set list_total = NULL
where
list_test1_scaled is null or list_test2_scaled is null
--update speak total
update DEC10assessmentData
set speak_total = (cast(speak_groupPres as decimal(3,1)) / 100 * 4
+ CAST(speak_indivPres as decimal(3,1)) / 100 * 8
+ cast(speak_tutorialDiscus as decimal(3,1)) / 100 * 8) / 20 * 100
where
TRY_CONVERT(decimal(3 , 1) , speak_groupPres) is not null and
TRY_CONVERT(decimal(3 , 1) , speak_indivPres) is not null and
TRY_CONVERT(decimal(3 , 1) , speak_tutorialDiscus) is not null
--update speak total where scores don't exist to null
update DEC10assessmentData
set speak_total = NULL
where
TRY_CONVERT(decimal(3 , 1) , speak_groupPres) is null or
TRY_CONVERT(decimal(3 , 1) , speak_indivPres) is null or
TRY_CONVERT(decimal(3 , 1) , speak_tutorialDiscus) is null
--update overall score
update DEC10assessmentData
set overall_total = (read_total + writ_total * 2 + list_total + speak_total) / 5
--update rec/not rec's for skills and overall
update DEC10assessmentData
set read_rec = t.rec_read, writ_rec = t.rec_writ, list_rec = t.rec_list, speak_rec = t.rec_speak, overall_rec = t.rec_overall
from dbo.udf_getDEC10RecSkillAndOverall() as t inner join DEC10assessmentData
on t.studentID = DEC10assessmentData.studentID and t.assessmentLookup = DEC10assessmentData.assessmentLookup
--update rec/not rec's for final rec
update DEC10assessmentData
set final_rec = t.rec_final
from dbo.udf_getDEC10RecFinal() as t inner join DEC10assessmentData
on t.studentID = DEC10assessmentData.studentID and t.assessmentLookup = DEC10assessmentData.assessmentLookup
END
GO
在获取表中其他列的更新后,我会触发计算表中的运行总计。正如您所看到的,遗憾的是很多varchar值的转换,但除了一个问题 - 锁定之外它还能完成这项工作。
我间歇性地让用户抱怨他们无法执行更新,这似乎是因为触发器锁定了表。有什么方法可以避免这种情况,我如何确认这是发生了什么?他们没有更新触发器更新的列。
我使用Erland Sommarskog的beta_lockinfo获得了两个死锁更新的以下输出:
rsctype locktype lstatus ownertype waittime spid waittype
KEY U WAIT TRANSACTION 2.192 LCK_M_U 69
DATABASE S grant STW 69
KEY X grant TRANSACTION 69
OBJECT IX grant TRANSACTION 69
PAGE IU grant TRANSACTION 69
PAGE IX grant TRANSACTION 69
KEY U WAIT TRANSACTION 2.188 LCK_M_U 89
DATABASE S grant STW 89
KEY X grant TRANSACTION 89
OBJECT IX grant TRANSACTION 89
PAGE IU grant TRANSACTION 89
PAGE IX grant TRANSACTION 89
答案 0 :(得分:1)
第一个建议应该是不要使用触发器并将业务逻辑移动到其他层。
您的更新会影响整个表,这可能会产生表锁:
update DEC10assessmentData
set overall_total = (read_total + writ_total * 2 + list_total + speak_total) / 5
etc
为什么要更新除已更改的行之外的其他行? How to work only on the updated row
为了您的计算,use calculated columns instead。
你真的需要做所有转换吗?您不能在表定义中修复数据类型吗?
但是,如果这是你绝对与触发器有关的事情,那么也许你可以重构你的表,这样你就不会将数据存储在同一个表中,而是存储在两个表中。这样,用户就可以更新他们的数据,并且可以更新您的数据。