1

我正在尝试分析一些棒球统计数据,但在实现看起来应该是一项简单的任务时遇到了一些麻烦。看一下以下结果集:

GAME_PK  REC_SEQ  BatterId  PlayNumber  EventType
287576   6        462101    1           single
287576   14       519048    2           single
287576   25       435079    3           strikeout
287576   26       435079    4           stolen_base_home
287576   28       435079    5           stolen_base_2b

PlayNumber 列是由我使用 ROW_NUMBER() OVER (ORDER BY GAME_PK, REC_SEQ) 生成的。其余的直接来自 MLB 统计数据库。REC_SEQ 是游戏内事件的序号。EventType 本质上是 at-bat 的结果。

我希望 PlayNumber 仅在 BatterId 更改时才增加。但它必须尊重 REC_SEQ 的顺序。所以我认为我不能使用 RANK 或 DENSE_RANK,但这些似乎非常接近我的需要。

我希望我的结果集如下所示:

GAME_PK  REC_SEQ  BatterId  PlayNumber  EventType
287576   6        462101    1           single
287576   14       519048    2           single
287576   25       435079    3           strikeout
287576   26       435079    3           stolen_base_home
287576   28       435079    3           stolen_base_2b

任何帮助表示赞赏。

谢谢!

编辑:在一场比赛中,击球手可以出现不止一次。每次出场都应该为他分配一个新的 PlayNumber。基本上,每个新的击球手都需要一个新的 PlayNumber。

4

2 回答 2

1

编辑:似乎可以完成的唯一方法是通过确定哪些顺序记录共享一个batterId来确定每个组的开始和结束位置。这是通过将记录与自身偏移 1 rownum 来确定每个组的开始位置来完成的。一旦我们收集了每个组的开头 ( GroupSets),我们就可以确定每个单独的记录属于哪个组以生成正确的编号:

with GroupSets as (
select
    row_number() over (order by s1.rec_seq) as rownum,
    s1.game_pk, s1.rec_seq, s1.batterid, s2.batterid as nextbatterid,
    s1.eventtype
from (select *, row_number() over (order by rec_seq) as rownum from stats) s1
left join (select rec_seq, batterid,
           row_number() over (order by rec_seq) as rownum from stats) s2
    on s1.rownum = s2.rownum + 1
where s1.batterid != s2.batterid or s2.batterid is null
)
select
    game_pk,
    rec_seq,
    batterid,
    (select max(rownum) from GroupSets gs where gs.Rec_Seq <= s1.rec_seq) as PlayNumber,
    eventtype
from
    stats s1;

演示:http ://www.sqlfiddle.com/#!3/a5e68/50


不处理交错的旧代码:

实际上该DENSE_RANK()功能应该做到这一点。但是,我们需要对MIN(REC_SEQ)每个 BatterId 组的值进行排名,以便用于REC_SEQ控制顺序。这样的事情应该这样做:

select
    s1.game_pk,
    s1.rec_seq,
    s1.batterID,
    dense_rank() over (order by s2.rec_seq) as PlayNumber,
    s1.EventType
from
    stats s1
join
    (select batterid, min(rec_seq) rec_seq
     from stats group by batterid) s2 on s1.batterid = s2.batterid
order by
    rec_seq

演示:http ://www.sqlfiddle.com/#!3/0682e/4

于 2012-04-20T17:13:17.423 回答
0

这很难,但在 SQL Server 中是可能的。我会注意到 Oracle 的分析功能使这变得更加容易。

思路如下:

  • 添加严格的序列号,以便您可以在每场比赛中获得上一场比赛
  • 使用它在给定序列中第一次击球时添加一个标志
  • 在游戏中枚举这些以获取游戏编号
  • 通过适当的组将其加入统计数据以分配正确的播放号码

我认为以下代码可以解决问题:

with s_enum as 
(
   select s.*, ROW_NUMBER() over (partition by game_pk order by rec_seq) as Seq
   from stats
) s_cp as 
(
   select s.*, ROW_NUMBER() over (partition by game_pk, FirstInSeq) as BattingSeq
   from 
   (
     select s.*,
        (case when prev.BatterId = curr.BatterId then 1 else 0 end) as FirstInSeq
     from s_enum curr 
     left outer join s_enum prev
        on curr.game_pk = prev.game_pk 
        and curr.Seq = prev.Seq + 1
   )
)
select s.game_pk, s.batterid, s.rec_seq, MAX(bs.req_sec) as PlayNumber       
from stats s 
join
(
   select s.*
   from s_cp s
   where FirstInSeq = 1
) bs
  on s.game_pk = bs.game_pk 
  and s.batterid = bs.batterid 
  and s.rec_seq >= bs.req_sec
group by s.game_pk, s.batterid, s.rec_seq
于 2012-04-20T18:22:27.787 回答