PHP项目统计高位逼抢夺回球权次数
这是一个足球数据分析的需求,下面给你一个完整的实现方案。

数据模型设计
首先需要设计数据库表结构:
-- 比赛表
CREATE TABLE matches (
id INT PRIMARY KEY AUTO_INCREMENT,
match_name VARCHAR(100),
match_date DATE
);
-- 球员表
CREATE TABLE players (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
team_id INT
);
-- 事件表(核心)
CREATE TABLE match_events (
id INT PRIMARY KEY AUTO_INCREMENT,
match_id INT,
player_id INT,
event_type VARCHAR(30), -- 事件类型
zone VARCHAR(20), -- 区域: defensive_third/middle_third/attacking_third
minute INT,
success TINYINT DEFAULT 1, -- 是否成功
created_at DATETIME,
INDEX idx_match (match_id),
INDEX idx_type (event_type)
);
-- 高位逼抢定义表(可配置)
CREATE TABLE pressing_rules (
id INT PRIMARY KEY AUTO_INCREMENT,
rule_name VARCHAR(50),
zone VARCHAR(20), -- 触发区域
event_types VARCHAR(200) -- 允许的事件类型, 逗号分隔
);
核心统计逻辑(PHP)
<?php
class HighPressStats
{
private PDO $pdo;
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
/**
* 统计某个球员/球队的高位逼抢夺回球权次数
*
* @param int $matchId 比赛ID (0=全部)
* @param int|null $playerId 球员ID (null=全队)
* @param int|null $teamId 球队ID
*/
public function countHighPressRecoveries(
int $matchId = 0,
?int $playerId = null,
?int $teamId = null
): array {
// 高位逼抢定义:在前场(attacking_third)或中场高压区
// 事件类型:抢断(tackle)、拦截(interception)、争抢成功(duel_won)、压迫成功(press_success)
$pressEventTypes = ['tackle', 'interception', 'duel_won', 'press_success'];
$highZones = ['attacking_third', 'middle_third'];
$sql = "SELECT
COUNT(*) AS total_recoveries,
COUNT(DISTINCT me.match_id) AS matches_count,
me.player_id,
p.name AS player_name
FROM match_events me
LEFT JOIN players p ON p.id = me.player_id
WHERE me.event_type IN (" . $this->placeholders($pressEventTypes) . ")
AND me.zone IN (" . $this->placeholders($highZones) . ")
AND me.success = 1";
$params = array_merge($pressEventTypes, $highZones);
if ($matchId > 0) {
$sql .= " AND me.match_id = ?";
$params[] = $matchId;
}
if ($playerId !== null) {
$sql .= " AND me.player_id = ?";
$params[] = $playerId;
}
if ($teamId !== null) {
$sql .= " AND p.team_id = ?";
$params[] = $teamId;
}
$sql .= " GROUP BY me.player_id, p.name
ORDER BY total_recoveries DESC";
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 统计总次数(单值)
*/
public function countTotal(int $matchId = 0, ?int $playerId = null): int
{
$result = $this->countHighPressRecoveries($matchId, $playerId);
return array_sum(array_column($result, 'total_recoveries'));
}
private function placeholders(array $arr): string
{
return implode(',', array_fill(0, count($arr), '?'));
}
}
使用示例
$pdo = new PDO('mysql:host=localhost;dbname=football', 'user', 'pass');
$stats = new HighPressStats($pdo);
// 1. 统计整场比赛的高位逼抢成功次数
$total = $stats->countTotal(matchId: 101);
echo "本场高位逼抢夺回球权: {$total} 次\n";
// 2. 按球员统计(某场比赛)
$players = $stats->countHighPressRecoveries(matchId: 101);
foreach ($players as $row) {
echo "{$row['player_name']}: {$row['total_recoveries']} 次\n";
}
// 3. 统计某球队整个赛季
$teamStats = $stats->countHighPressRecoveries(matchId: 0, teamId: 5);
关键设计说明
| 要点 | 说明 |
|---|---|
| 区域判定 | 高位逼抢通常在 attacking_third(对方半场)和 middle_third,需根据球队战术调整 |
| 事件类型 | press_success(压迫成功)、tackle、interception、duel_won 组合统计 |
| 幂等统计 | 建议在事件写入后做一次去重,避免同一次抢断被多次记录 |
| 性能优化 | 事件表数据量大时可加 (match_id, event_type, zone) 复合索引,或做汇总表 |
进阶:汇总表(大数据量推荐)
-- 每日/每场汇总,避免每次实时聚合
CREATE TABLE high_press_summary (
id INT PRIMARY KEY AUTO_INCREMENT,
match_id INT,
player_id INT,
team_id INT,
recoveries INT DEFAULT 0,
updated_at DATETIME,
UNIQUE KEY uk (match_id, player_id)
);
在事件入库时通过触发器或业务代码增量更新汇总表,查询时直接读取即可。
如果你能补充以下信息,我可以给出更精确的实现:
- 你的数据源格式(CSV导入?API?手工录入?)
- "高位逼抢"的具体判定规则(是否按坐标区域?)
- 是否需要按赛季/球队/球员多维度报表