【问题标题】:Creating triggers in order to implement ranking on a table创建触发器以在表上实现排名
【发布时间】:2012-04-10 13:05:46
【问题描述】:

我从未在 SQL Server 2008 中使用过触发器。所以我不知道如何去做。

我有一个游戏应用程序,我正在跟踪所玩问题的数量和正确回答的问题总数。我还节省了每个问题的平均时间。

现在我想根据正确答案的百分比记录排名,如果出现平局,我们将检查所用时间。我必须使用触发器来完成所有这些操作。

  id   | playerID | CompetitionID  | NoOfCOrrectANswers | NoOfPlayedQuestions | TimeTaken 
-----------------------------------------------------------------------------------------
  1      3             203              4                       8                  8.4
  2      56            203              9                      18                 13
  3      67            203              16                     45                 15

感谢任何帮助。提前致谢。

【问题讨论】:

  • 首先创建一个简单的触发器来了解它们的工作原理,然后构建到更复杂的触发器中。当您的触发器未按预期运行时,请在此处发布代码,人们可以提供帮助
  • 只是一个想法。为什么不只跟踪原始数据,这样玩家 1 在 2 秒内回答了问题 1,依此类推。然后在计算平均值等的表顶部创建一个视图。您还可以在视图中使用 SQL 2008 rank 函数。当一个表经常被重击时,触发器可能会成为性能杀手。通过视图,您将能够在需要时且仅在需要时计算所需的值。
  • 如果您可以添加源表的定义,即包含玩家如何回答数据的表和目标表定义,我可能会为您提供更多帮助。如果没有表定义,我将无济于事。
  • 很抱歉我忘了提及,但我已经在表格中添加了 PlayerRank 字段。以下是我对触发器的所有要求/条件: 1. 每当向表中添加新行时,我们都需要更新具有相同 COmpetitionID 的所有记录的排名 2. 回答更多没有正确答案的玩家将有更好的rank 可能是 Rank 1。 3. 如果两个玩家的号码相同。的正确答案,然后我们将寻找所花费的时间。花费时间价值较少的玩家将有更好的排名,如果他们有相同的时间,那么他们将拥有相同的排名。我希望现在一切都清楚了...

标签: sql-server sql-server-2008 triggers


【解决方案1】:

您可能不应该走这条路,因为更新的数量会很高。您可以将row_number()rank() 函数添加到显示比赛结果的查询中。

话虽如此,如果您觉得绝对必须在表格中保留排名信息,请添加一列

alter table ATable add PlayerRank int

并在 ATable 上创建触发器

create trigger RankingTrigger on ATable
after insert, update, delete
as
-- We don't want queries in a trigger to mess up with "Rows affected"
   set nocount on
-- If any of the following columns are mentioned in a query
-- Always true for insert and delete, but we will save updates
-- if we skip processing when columns participating in ranking 
-- are not changed
   If update (NoOfCOrrectANswers)
      OR update(NoOfPlayedQuestions)
      OR update(TimeTaken)
   begin
      -- CTE that returns primary key and rank by competition.
      -- I've changed your condition (percent of correct answers)
      -- As it would rank players with one correct answer over those
      -- who answered 100 questions and got only one wrong. If you
      -- want to change it, replace NoOfCOrrectANswers with 
      -- NoOfCOrrectANswers / NoOfPlayedQuestions
      ; with theRank as (
        select ID, row_number() over (partition by CompetitionID
                                      order by NoOfCOrrectANswers DESC,
                                               TimeTaken DESC) rn
          from ATable
      -- Only changed competitions
         where CompetitionID in
      -- Inserted table is available in trigger and OUTPUT clause
      -- of insert, update, delete statements.
      -- It contains newly added/changed rows
      -- We are using it here to filter only changed competitions
      -- Similary, Deleted table hold a copy of removed rows for delete 
      -- and old values for update
         (
            select CompetitionID
              from Inserted
            union
            select CompetitionID
              from Deleted
         )
      )
      update ATable
      -- Update to rank from theRank CTE
         set PlayerRank = theRank.rn
        from ATable
        -- All records participation in affected competitions
          inner join theRank
             on ATable.ID = theRank.ID
        -- Only change if really changed
        -- This part is very likely not needed. I have never tested
        -- to see if it affects performance
            and isnull(ATable.PlayerRank, 0) <> theRank.rn
   end

【讨论】:

  • 视图中的 CTE 可能不会是性能杀手,所以我同意触发器可能不是要走的路。哦,顺便说一句,您在回答中说-插入的表仅在触发器中可用。如果使用 OUTPUT 子句,则可以访问自 2005 年以来在 UPDATE、INSERT 和 DELETE 语句中插入和删除的表。我发现输出子句是那些隐藏的 SQL gem 之一。
  • @Namphibian 感谢您指出这个错误。它让我忘记了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-31
  • 1970-01-01
  • 1970-01-01
  • 2014-08-09
相关资源
最近更新 更多