sql-server – 在MS SQL触发器中处理多个记录

前端之家收集整理的这篇文章主要介绍了sql-server – 在MS SQL触发器中处理多个记录前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我不得不第一次在MSsql中使用触发器,一般来说是很好的触发器.阅读并自己测试后,我现在意识到触发器会触发每个命令,而不是每行插入,删除或更新.

整个事情是广告系统的一些统计数据.我们的主要统计表相当大,并且在大多数情况下不包含有意义的数据.它包含每个广告点击,查看等一行.作为用户,更倾向于想要查看它,因为日X具有Y点击量和Z量视图等等.到目前为止,我们完全基于SQL查询完成了这一点,从主表中获取此类报告,但随着表的增长,该查询的执行时间也增加了.因此,我们选择使用触发器来更新另一个表,从而使sql服务器上的这一点变得更容易.

我现在的问题是使用多个记录.我所做的是创建2个存储过程,一个用于处理插入操作,另一个用于删除.我的插入触发器(写入使用单个记录)然后从Inserted表中删除数据,并将其发送到存储过程.删除触发器以相同的方式工作,并且(显然?)更新触发器与删除插入操作相同.

我现在的问题是如何使用多个记录来做到这一点.我已经尝试过使用光标,但就我能够阅读和看到自己而言,这表现得非常糟糕.我也考虑过编写一些“检查” – 比如检查命令中是否有多条记录,然后继续使用光标,否则只是避免这种情况.无论如何,这是我的光标解决方案,我想知道是否有更好的方法吗?

  1. CREATE TRIGGER [dbo].[TR_STAT_INSERT]
  2. ON [iqdev].[dbo].[Stat]
  3. AFTER INSERT
  4. AS
  5. BEGIN
  6. SET NOCOUNT ON;
  7.  
  8. DECLARE @Date DATE
  9. DECLARE @CampaignId BIGINT
  10. DECLARE @CampaignName varchar(500)
  11. DECLARE @AdvertiserId BIGINT
  12. DECLARE @PublisherId BIGINT
  13. DECLARE @Unique BIT
  14. DECLARE @Approved BIT
  15. DECLARE @PublisherEarning money
  16. DECLARE @AdvertiserCost money
  17. DECLARE @Type smallint
  18.  
  19. DECLARE InsertCursor CURSOR FOR SELECT Id FROM Inserted
  20. DECLARE @curId bigint
  21.  
  22. OPEN InsertCursor
  23.  
  24. FETCH NEXT FROM InsertCursor INTO @curId
  25.  
  26. WHILE @@FETCH_STATUS = 0
  27. BEGIN
  28.  
  29. SELECT @Date = [Date],@PublisherId = [PublisherCustomerId],@Approved = [Approved],@Unique = [Unique],@Type = [Type],@AdvertiserCost = AdvertiserCost,@PublisherEarning = PublisherEarning
  30. FROM Inserted
  31. WHERE Id = @curId
  32.  
  33. SELECT @CampaignId = T1.CampaignId,@CampaignName = T2.Name,@AdvertiserId = T2.CustomerId
  34. FROM Advert AS T1
  35. INNER JOIN Campaign AS T2 on T1.CampaignId = T2.Id
  36. WHERE T1.Id = (SELECT AdvertId FROM Inserted WHERE Id = @curId)
  37.  
  38. EXEC ProcStatInsertTrigger @Date,@CampaignId,@CampaignName,@AdvertiserId,@PublisherId,@Unique,@Approved,@PublisherEarning,@AdvertiserCost,@Type
  39.  
  40. FETCH NEXT FROM InsertCursor INTO @curId
  41. END
  42.  
  43. CLOSE InsertCursor
  44. DEALLOCATE InsertCursor
  45. END

存储过程相当大而且强烈,我不认为有必要避免以某种方式循环遍历Inserted表的记录(好吧,也许有,但我希望能够阅读代码也是:p),所以我不会厌倦那个(除非你不想另外考虑).所以,有没有更好的方法来做到这一点,如果是这样,怎么样?

编辑:请求后,这是sproc

  1. CREATE PROCEDURE ProcStatInsertTrigger
  2. @Date DATE,@CampaignId BIGINT,@CampaignName varchar(500),@AdvertiserId BIGINT,@PublisherId BIGINT,@Unique BIT,@Approved BIT,@PublisherEarning money,@AdvertiserCost money,@Type smallint
  3. AS
  4. BEGIN
  5. -- SET NOCOUNT ON added to prevent extra result sets from
  6. -- interfering with SELECT statements.
  7. SET NOCOUNT ON;
  8. IF @Approved = 1
  9. BEGIN
  10. DECLARE @test bit
  11.  
  12. SELECT @test = 1 FROM CachedStats WHERE [Date] = @Date AND CampaignId = @CampaignId AND CustomerId = @PublisherId
  13.  
  14. IF @test IS NULL
  15. BEGIN
  16. INSERT INTO CachedStats ([Date],CustomerId,CampaignId,CampaignName) VALUES (@Date,@CampaignName)
  17. END
  18.  
  19. SELECT @test = NULL
  20.  
  21. DECLARE @Clicks int
  22. DECLARE @TotalAdvertiserCost money
  23. DECLARE @TotalPublisherEarning money
  24. DECLARE @PublisherCPC money
  25. DECLARE @AdvertiserCPC money
  26.  
  27. SELECT @Clicks = Clicks,@TotalAdvertiserCost = AdvertiserCost + @AdvertiserCost,@TotalPublisherEarning = PublisherEarning + @PublisherEarning FROM CachedStats
  28. WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId
  29.  
  30. IF @Type = 0 -- If click add one to the calculation
  31. BEGIN
  32. SELECT @Clicks = @Clicks + 1
  33. END
  34.  
  35. IF @Clicks > 0
  36. BEGIN
  37. SELECT @PublisherCPC = @TotalPublisherEarning / @Clicks,@AdvertiserCPC = @TotalAdvertiserCost / @Clicks
  38. END
  39. ELSE
  40. BEGIN
  41. SELECT @PublisherCPC = 0,@AdvertiserCPC = 0
  42. END
  43. IF @Type = 0
  44. BEGIN
  45.  
  46. UPDATE CachedStats SET
  47. Clicks = @Clicks,UniqueClicks = UniqueClicks + @Unique,PublisherEarning = @TotalPublisherEarning,AdvertiserCost = @TotalAdvertiserCost,PublisherCPC = @PublisherCPC,AdvertiserCPC = @AdvertiserCPC
  48. WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId
  49. END
  50. ELSE IF @Type = 1 OR @Type = 4 -- lead or coreg
  51. BEGIN
  52. UPDATE CachedStats SET
  53. Leads = Leads + 1,AdvertiserCPC = @AdvertiserCPC,PublisherCPC = @AdvertiserCPC
  54. WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId
  55. END
  56. ELSE IF @Type = 3 -- Isale
  57. BEGIN
  58. UPDATE CachedStats SET
  59. Leads = Leads + 1,PublisherCPC = @AdvertiserCPC,AdvertiserOrderValue = @AdvertiserCost,PublisherOrderValue = @PublisherEarning
  60. WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId
  61. END
  62. ELSE IF @Type = 2 -- View
  63. BEGIN
  64. UPDATE CachedStats SET
  65. [Views] = [Views] + 1,UniqueViews = UniqueViews + @Unique,AdvertiserCPC = @AdvertiserCPC
  66. WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId
  67. END
  68. END
  69. END

在帮助之后,这是我的最终结果,以防其他人有类似的问题

  1. CREATE TRIGGER [dbo].[TR_STAT_INSERT]
  2. ON [iqdev].[dbo].[Stat]
  3. AFTER INSERT
  4. AS
  5. BEGIN
  6.  
  7. SET NOCOUNT ON
  8.  
  9. -- insert all missing "CachedStats" rows
  10. INSERT INTO
  11. CachedStats ([Date],AdvertId,CampaignName)
  12. SELECT DISTINCT
  13. CONVERT(Date,i.[Date]),i.AdvertId,i.[PublisherCustomerId],c.Id,c.Name
  14. FROM
  15. Inserted i
  16. INNER JOIN Advert AS a ON a.Id = i.AdvertId
  17. INNER JOIN Campaign AS c ON c.Id = a.CampaignId
  18. WHERE
  19. i.[Approved] = 1
  20. AND NOT EXISTS (
  21. SELECT 1
  22. FROM CachedStats as t
  23. WHERE
  24. [Date] = CONVERT(Date,i.[Date])
  25. AND CampaignId = c.Id
  26. AND CustomerId = i.[PublisherCustomerId]
  27. AND t.AdvertId = i.AdvertId
  28. )
  29.  
  30. -- update all affected records at once
  31. UPDATE
  32. CachedStats
  33. SET
  34. Clicks =
  35. Clicks + (
  36. SELECT COUNT(*) FROM Inserted s
  37. WHERE s.Approved = 1
  38. AND s.PublisherCustomerId = i.PublisherCustomerId
  39. AND CONVERT(Date,s.[Date]) = CONVERT(Date,i.[Date])
  40. AND s.AdvertId = i.AdvertId
  41. AND s.[Type] = 0
  42. ),UniqueClicks =
  43. UniqueClicks + (
  44. SELECT COUNT(*) FROM Inserted s
  45. WHERE s.Approved = 1
  46. AND s.[Unique] = 1
  47. AND s.PublisherCustomerId = i.PublisherCustomerId
  48. AND CONVERT(Date,[Views] =
  49. [Views] + (
  50. SELECT COUNT(*) FROM Inserted s
  51. WHERE s.Approved = 1
  52. AND s.PublisherCustomerId = i.PublisherCustomerId
  53. AND CONVERT(Date,i.[Date])
  54. AND s.AdvertId = i.AdvertId
  55. AND s.[Type] = 2
  56. ),UniqueViews =
  57. UniqueViews + (
  58. SELECT COUNT(*) FROM Inserted s
  59. WHERE s.Approved = 1
  60. AND s.[Unique] = 1
  61. AND s.PublisherCustomerId = i.PublisherCustomerId
  62. AND CONVERT(Date,Leads =
  63. Leads + (
  64. SELECT COUNT(*) FROM Inserted s
  65. WHERE s.Approved = 1
  66. AND s.[Unique] = 1
  67. AND s.PublisherCustomerId = i.PublisherCustomerId
  68. AND CONVERT(Date,i.[Date])
  69. AND s.AdvertId = i.AdvertId
  70. AND s.[Type] IN (1,3,4)
  71. ),PublisherEarning =
  72. CachedStats.PublisherEarning + ISNULL((
  73. SELECT SUM(PublisherEarning) FROM Inserted s
  74. WHERE s.Approved = 1
  75. AND s.PublisherCustomerId = i.PublisherCustomerId
  76. AND CONVERT(Date,i.[Date])
  77. AND s.AdvertId = i.AdvertId
  78.  
  79. ),0),AdvertiserCost =
  80. CachedStats.AdvertiserCost + ISNULL((
  81. SELECT SUM(AdvertiserCost) FROM Inserted s
  82. WHERE s.Approved = 1
  83. AND s.PublisherCustomerId = i.PublisherCustomerId
  84. AND CONVERT(Date,i.[Date])
  85. AND s.AdvertId = i.AdvertId
  86. ),PublisherOrderValue =
  87. PublisherOrderValue + ISNULL((
  88. SELECT SUM(PublisherEarning) FROM Inserted s
  89. WHERE s.Approved = 1
  90. AND s.PublisherCustomerId = i.PublisherCustomerId
  91. AND CONVERT(Date,i.[Date])
  92. AND s.AdvertId = i.AdvertId
  93. AND s.[Type] = 3
  94. ),AdvertiserOrderValue =
  95. AdvertiserOrderValue + ISNULL((
  96. SELECT SUM(AdvertiserCost) FROM Inserted s
  97. WHERE s.Approved = 1
  98. AND s.PublisherCustomerId = i.PublisherCustomerId
  99. AND CONVERT(Date,i.[Date])
  100. AND s.AdvertId = i.AdvertId
  101. AND s.[Type] = 3
  102. ),PublisherCPC =
  103. CASE WHEN (Clicks + (
  104. SELECT COUNT(*) FROM Inserted s
  105. WHERE s.Approved = 1
  106. AND s.PublisherCustomerId = i.PublisherCustomerId
  107. AND CONVERT(Date,i.[Date])
  108. AND s.AdvertId = i.AdvertId
  109. AND s.[Type] = 0
  110. )) > 0 THEN
  111. (CachedStats.PublisherEarning + ISNULL((
  112. SELECT SUM(PublisherEarning) FROM Inserted s
  113. WHERE s.Approved = 1
  114. AND s.PublisherCustomerId = i.PublisherCustomerId
  115. AND CONVERT(Date,i.[Date])
  116. AND s.AdvertId = i.AdvertId
  117. ),0)) -- COST ^
  118. / (
  119. Clicks + (
  120. SELECT COUNT(*) FROM Inserted s
  121. WHERE s.Approved = 1
  122. AND s.PublisherCustomerId = i.PublisherCustomerId
  123. AND CONVERT(Date,i.[Date])
  124. AND s.AdvertId = i.AdvertId
  125. AND s.[Type] = 0
  126. )
  127. ) --- Clicks ^
  128. ELSE
  129. 0
  130. END,AdvertiserCPC =
  131. CASE WHEN (Clicks + (
  132. SELECT COUNT(*) FROM Inserted s
  133. WHERE s.Approved = 1
  134. AND s.PublisherCustomerId = i.PublisherCustomerId
  135. AND CONVERT(Date,i.[Date])
  136. AND s.AdvertId = i.AdvertId
  137. AND s.[Type] = 0
  138. )) > 0 THEN
  139. (CachedStats.AdvertiserCost + ISNULL((
  140. SELECT SUM(AdvertiserCost) FROM Inserted s
  141. WHERE s.Approved = 1
  142. AND s.PublisherCustomerId = i.PublisherCustomerId
  143. AND CONVERT(Date,i.[Date])
  144. AND s.AdvertId = i.AdvertId
  145. AND s.[Type] = 0
  146. )
  147. ) --- Clicks ^
  148. ELSE
  149. 0
  150. END
  151. FROM
  152. Inserted i
  153. WHERE
  154. i.Approved = 1 AND
  155. CachedStats.Advertid = i.AdvertId AND
  156. CachedStats.[Date] = Convert(Date,i.[Date]) AND
  157. CachedStats.CustomerId = i.PublisherCustomerId
  158. SET NOCOUNT OFF
  159. END

它现在看起来略有不同,因为我也必须为每个广告编制索引 – 但非常感谢帮助 – 从30小时到30秒加速所有内容从我自己的开发Stat表生成CachedStats

猜你在找的MsSQL相关文章