动态地在参赛者之间分配奖品

时间:2014-09-27 10:33:12

标签: c# sql sql-server

这真让我大吃一惊。我创建了一个联盟,我根据参赛者数量的最小和最大位置来定义奖品,即:

LeagueSizeID    LeagueSizeMin    LeagueSizeMax
     1                1               24
     2                25              49
     3                500             999

这涉及一个定义每个联赛的支出的表,这是leaguesizeid 3的例子

    LeaguesizeID    PositionMin PositionMax WinPerc
       3                  1         1        22.00
       3                  2         2        10.00
       3                  3         3         7.00
       3                  4         4         6.00
       3                  5         5         5.00
       3                  6         6         4.00
       3                  7         7         3.50
       3                  8         8         3.00
       3                  9         9         2.50
       3                  10        10        2.00
       3                  11        20        1.00
       3                  21        30        0.50

我采取的方法是循环每个位置并获得与该位置匹配的参赛者。我的问题是可以有联合赢家。如果有联合获胜者,那么第二名奖金需要考虑。所以对于以下结果:

UserID    Position    Prize
  1          1         22.0%
  2          2         10
  3          3         6.5   // joint here so takes position 3 and 4 
  4          3         6.5   // and splits prize
  5          4         5 % // this is now position 5

我正在使用DenseRank()是SQL来排序位置但是我可能需要将其更改为Rank(),除非有人能指出我在算法的正确方向上从数据库对象驱动吗?

提前致谢!

1 个答案:

答案 0 :(得分:0)

我希望创建两个中间结果集。首先rank_bounds。这具有该等级的用户ID,等级和关系数。第二个是exploded_payout。每个支付位置都有一行,而不是累积到最小和最大位置。一旦你有了这个,你可以很容易地获得支付百分比。

我使用常用​​的表格表达式(并简化并填写了一些缺少的表格详细信息)将它们全部放在一起:

with ranks as (
  select
    UserID,
    rank() over (order by Score desc) rk
  from
    UserGameScores
  where
    GameID = 1
), rank_bounds as (
  select
    UserID,
    rk Position,
    count(1) over (partition by rk) as TieCount
  from
    ranks
), n as (
  select
    row_number() over (order by number) rn
  from
    -- if you have lots of payout lines, you might need more numbers than this
    master..spt_values
), exploded_payout as (
  select
    n.rn as Position,
    p.WinPerc
  from
    Payout p
      inner join
    n
      on p.PositionMin <= n.rn and p.PositionMax >= n.rn
) select
  UserId,
  avg(winperc)
from
  exploded_payout xp
    inner join
  rank_bounds rb
    on xp.Position >= rb.Position and
       xp.Position < rb.Position + rb.TieCount
group by
  UserId;

如果你想在结果集中得到排名,你需要将最后一位放入CTE并再次加入排名表。

虽然SQL有点难以理解。我不确定程序方法会简单得多。此外,SQL具有很好的属性,可以很容易地一次扩展到所有游戏:)

Example SQLFiddle