如何在没有循环或游标的情况下推广顺序COUNT()的时间顺序数据?

Rou*_*ker 5 mysql sql procedural-programming cursor nested-loops

我已经阅读了所有的论点:告诉SQL你想要什么,而不是如何得到它.使用基于集合的方法而不是程序逻辑.不惜一切代价避免使用游标和循环.

不幸的是,我已经绞尽脑汁几周了,我无法弄清楚如何提出一种基于集合的方法来COUNT为按顺序排列的时间顺序数据子集生成迭代.

以下是我正在处理的问题的具体应用.

我使用包含多年播放数据的数据库进行与足球相关的研究,该数据当然按时间顺序按年,游戏和比赛排列.数据库加载到运行MySQL 5.0的Web服务器上.

core表格中包含了我对此特定问题所需的字段.以下是表格相关部分的一些示例数据:

   GID | PID  | OFF | DEF | QTR | MIN | SEC | PTSO | PTSD
  --------------------------------------------------------
   121 | 2455 | ARI | CHI |   2 |   4 |  30 |   17 |   10
   121 | 2456 | ARI | CHI |   2 |   4 |  15 |   17 |   10 
   121 | 2457 | ARI | CHI |   2 |   3 |  53 |   17 |   10 
   121 | 2458 | ARI | CHI |   2 |   3 |  31 |   20 |   10 
Run Code Online (Sandbox Code Playgroud)

这些列分别代表:独特的游戏标识符,唯一的游戏标识符,哪个团队正在进行该游戏,哪个团队正在为该游戏进行防御,该游戏发生的季度和时间,以及进入该游戏的进攻和防守分数.换句话说,在(假设的)游戏121中,亚利桑那红雀队在比赛2457上进球(即,进入比赛2458).

我想要做的是逐个游戏,逐秒进行数年的数据游戏,并计算在任何给定的经过时间内任何可能的分数差异发生的次数.以下查询按经过的秒数和分数差异排列数据:

SELECT core.GID, core.PID, core.QTR, core.MIN, core.SEC, core.PTSO, core.PTSD, 
    ((core.QTR - 1) * 900 + (900-(core.MIN * 60 + core.SEC))) AS secEl, 
    core.PTSO - core.PTSD AS oDif, (core.PTSO - core.PTSD) * -1 AS dDif
FROM core 
ORDER BY secEl ASC, oDif ASC;
Run Code Online (Sandbox Code Playgroud)

结果看起来像这样:

   GID | PID    | OFF | DEF | QTR | MIN | SEC | PTSO | PTSD | secEl | oDif | dDif
 ---------------------------------------------------------------------------------
   616 | 100022 | CHI | MIN |   1 |  15 |  00 |    0 |    0 |     0 |    0 |    0
   617 | 100169 | HOU | DAL |   1 |  15 |  00 |    0 |    0 |     0 |    0 |    0
   618 | 100224 | PHI | SEA |   1 |  15 |  00 |    0 |    0 |     0 |    0 |    0
   619 | 100303 | JAX | NYJ |   1 |  15 |  00 |    0 |    0 |     0 |    0 |    0 
Run Code Online (Sandbox Code Playgroud)

虽然看起来很漂亮,但我的目标不是按时间顺序对数据进行排序.相反,我想在NFL比赛中按顺序逐步完成4,500个可能的秒数(四个15分钟的季度加上一个15分钟的加班时间)中的每一个,并计算每个分数中每个分数差异发生的次数.秒.

换句话说,我不想仅仅计算一支球队在2002年至2013年间经过1,800秒(即第二季度开始)的21分的数量.我想数一数一个团队在游戏中任何一点上升21点的次数.最重要的是,我想为每一个曾经发生的分数差异做这个(即-50,-49,-48,...,0,1,2,... 48,49,50,... ..)每场比赛的每一秒.

使用一系列嵌套循环可以相对容易地完成,但它不是最可重用的代码.

我想要做的是构造设置逻辑,COUNT该逻辑将在使用循环或游标的情况下每隔一秒钟发生的每个得分差异的实例.结果将列表如下:

   secondsElapsed | scoreDif | Occurrences
  -----------------------------------------
               10 |       -1 |          12
               10 |        0 |      125517
               10 |        1 |           0
               10 |        2 |           3
Run Code Online (Sandbox Code Playgroud)

以下是获取特定时间点(经过3,000秒)的特定分数差异(+21)实例总数的示例查询:

SELECT ((core.QTR - 1) * 900 + (900-(core.MIN * 60 + core.SEC))) AS timeElapsed, 
    (core.PTSO - core.PTSD) AS diff, COUNT(core.PTSO - core.PTSD) AS occurrences 
FROM core 
WHERE ((core.QTR - 1) * 900 + (900-(core.MIN * 60 + core.SEC))) = 3000 
    AND ABS(core.PTSO - core.PTSD) = 21
Run Code Online (Sandbox Code Playgroud)

该查询返回以下结果:

   timeElapsed | diff | occurrences
  ----------------------------------
          3000 |   21 |           5 
Run Code Online (Sandbox Code Playgroud)

现在我想概括这个查询来计算一次经过的每个差异的实例.

sar*_*rin 0

您的描述相当混乱,但如果您想“在不使用循环或游标的情况下计算每一可能秒内所有可能的分数差异”,那么我会这样做:

1)构建一个工作表(临时表#或表数据类型@)并用您想要的时间增量填充它,例如

   QTR | MIN | SEC |  
    1 |  00 |  01
    1 |  00 |  02
..
    1 |  01 |  59
    1 |  02 |  00
    1 |  02 |  01
    1 |  02 |  02
..
    4 |  15 |  59 
Run Code Online (Sandbox Code Playgroud)

2) 然后您可以使用它作为查询的基础。将您感兴趣的游戏列表与工作表交叉连接,为您提供每场比赛以及该比赛中每一分钟的表格。

3)将(2)的结果左连接到上面的查询中?

有了这个结果集,您就可以查看整个游戏并根据需要进行求和\计数,而无需循环。