php项目统计犯规战术阻止反击几次?

wen PHP项目 4

PHP项目统计“犯规战术阻止反击”次数方案

你这个问题比较简短,我先按足球/篮球比赛数据统计系统的常见需求来理解:统计一支球队通过犯规来阻止对手快攻/反击的次数,下面给出完整可落地的 PHP 实现方案。

php项目统计犯规战术阻止反击几次?


需求拆解

要素 说明
事件主体 防守方球员/球队
犯规类型 战术犯规(非体育道德、非冲球)
情境条件 对手处于反击/快攻状态(Fast Break)
统计目标 次数(COUNT),可按球员、球队、时间段聚合

关键点:不是所有犯规都算,必须满足“阻止反击”这一情境,所以需要事件表里带 is_fast_break 或 counter_attack 标志。


数据库设计(MySQL)

-- 比赛事件表(通用)
CREATE TABLE match_events (
    id            BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    match_id      BIGINT UNSIGNED NOT NULL,
    team_id       BIGINT UNSIGNED NOT NULL,
    player_id     BIGINT UNSIGNED NOT NULL,
    event_type    ENUM('foul','shot','pass','turnover') NOT NULL,
    foul_type     ENUM('normal','tactical','unsportsmanlike','technical') NULL,
    is_fast_break TINYINT(1) NOT NULL DEFAULT 0,  -- 是否处于对手反击情境
    period        TINYINT NOT NULL,               -- 第几节/半场
    event_time    INT NOT NULL,                   -- 比赛进行秒数
    created_at    TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_match_team (match_id, team_id),
    INDEX idx_foul (event_type, foul_type, is_fast_break)
);

如果已有事件表,只需补 foul_type 和 is_fast_break 两个字段。


核心统计 SQL

单场:某队“犯规阻止反击”次数

SELECT COUNT(*) AS stop_counter_count
FROM match_events
WHERE match_id = :match_id
  AND team_id  = :team_id
  AND event_type = 'foul'
  AND foul_type = 'tactical'
  AND is_fast_break = 1;

按球员聚合(单场)

SELECT player_id, COUNT(*) AS cnt
FROM match_events
WHERE match_id = :match_id
  AND event_type = 'foul'
  AND foul_type = 'tactical'
  AND is_fast_break = 1
GROUP BY player_id
ORDER BY cnt DESC;

赛季累计(按球队)

SELECT t.id, t.name, COUNT(e.id) AS total
FROM teams t
LEFT JOIN match_events e
       ON e.team_id = t.id
      AND e.event_type = 'foul'
      AND e.foul_type = 'tactical'
      AND e.is_fast_break = 1
LEFT JOIN matches m ON m.id = e.match_id
WHERE m.season_id = :season_id
GROUP BY t.id, t.name
ORDER BY total DESC;

PHP 实现(PDO,带参数绑定)

<?php
class FoulStats
{
    private PDO $pdo;
    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }
    /** 单场某队“犯规阻止反击”次数 */
    public function stopCounterCount(int $matchId, int $teamId): int
    {
        $sql = "SELECT COUNT(*) FROM match_events
                WHERE match_id = :mid
                  AND team_id  = :tid
                  AND event_type = 'foul'
                  AND foul_type = 'tactical'
                  AND is_fast_break = 1";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':mid' => $matchId, ':tid' => $teamId]);
        return (int) $stmt->fetchColumn();
    }
    /** 单场按球员统计 */
    public function stopCounterByPlayer(int $matchId): array
    {
        $sql = "SELECT player_id, COUNT(*) AS cnt
                FROM match_events
                WHERE match_id = :mid
                  AND event_type = 'foul'
                  AND foul_type = 'tactical'
                  AND is_fast_break = 1
                GROUP BY player_id
                ORDER BY cnt DESC";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':mid' => $matchId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    /** 赛季按球队统计 */
    public function seasonTeamStats(int $seasonId): array
    {
        $sql = "SELECT t.id, t.name, COUNT(e.id) AS total
                FROM teams t
                LEFT JOIN match_events e ON e.team_id = t.id
                     AND e.event_type  = 'foul'
                     AND e.foul_type   = 'tactical'
                     AND e.is_fast_break = 1
                LEFT JOIN matches m ON m.id = e.match_id AND m.season_id = :sid
                WHERE m.id IS NOT NULL OR e.id IS NULL
                GROUP BY t.id, t.name
                ORDER BY total DESC";
        // 注意:上面 LEFT JOIN 写法容易漏球队,推荐用子查询版本(见下)
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([':sid' => $seasonId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

更稳妥的赛季统计(避免 JOIN 漏队):

SELECT t.id, t.name,
       (SELECT COUNT(*)
        FROM match_events e
        JOIN matches m ON m.id = e.match_id
        WHERE e.team_id = t.id
          AND m.season_id = :sid
          AND e.event_type = 'foul'
          AND e.foul_type = 'tactical'
          AND e.is_fast_break = 1) AS total
FROM teams t
ORDER BY total DESC;

录入侧的关键逻辑

统计准确性取决于录入时如何判定 is_fast_break,建议:

  1. 赛中/赛后人工标注:录像回看打标签(最可靠)。
  2. 规则引擎自动判定(若有逐回合数据):
    • 对方得球后 N 秒内(如 ≤8s)形成推进;
    • 进攻方人数 ≥ 防守方 或 推进速度超阈值;
    • 此时发生犯规 → 标记 is_fast_break = 1。

示例伪代码:

function judgeFastBreak(array $possession, int $foulTime): bool
{
    $gainTime = $possession['gain_time'];
    $advance  = $possession['advanced_meters'];
    return ($foulTime - $gainTime) <= 8 && $advance >= 15;
}

录入接口:

$isFastBreak = judgeFastBreak($possession, $eventTime);
$stmt = $pdo->prepare(
    "INSERT INTO match_events
     (match_id, team_id, player_id, event_type, foul_type, is_fast_break, period, event_time)
     VALUES (?,?,?,?,?,?,?,?)"
);
$stmt->execute([$matchId, $teamId, $playerId, 'foul', 'tactical',
                $isFastBreak ? 1 : 0, $period, $eventTime]);

易错点提醒

坑 说明
把普通犯规算进去 必须过滤 foul_type='tactical'(或你定义的战术犯规枚举)
反击判定缺失 没有 is_fast_break 字段就无法区分,必须补
同一回合多次犯规 用 possession_id 去重,避免重复计数
赛季统计漏队 用子查询而非链式 LEFT JOIN
时区/时间 统计按 match_id 聚合即可,避免用 created_at 过滤比赛时间

如果你问的不是体育场景

“犯规战术阻止反击”也可能是游戏(如王者荣耀/CS)或安全攻防演练里的术语,如果是:

  • 游戏对战统计:把 match_events 换成 battle_logs,字段改为 action_type='foul_tactic'、context='counter',SQL 思路完全一致。
  • 网络攻防演练:这里“犯规”≈“拦截/阻断”,“反击”≈“attacker 的横向移动”,统计的是 blocked_attack_chain 次数。

请确认你的具体场景(足球?篮球?游戏?安全?),以及是否已有事件表结构,我可以把 SQL 和 PHP 改成完全贴合你现有模型的版本。

抱歉,评论功能暂时关闭!