PHP项目:统计传球成功率哪队更高
下面给你一个完整的 PHP 实现方案,包含数据模型、统计逻辑和示例代码。

数据表设计(MySQL)
-- 球队表
CREATE TABLE teams (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL
);
-- 比赛表
CREATE TABLE matches (
id INT PRIMARY KEY AUTO_INCREMENT,
home_team_id INT NOT NULL,
away_team_id INT NOT NULL,
match_date DATE
);
-- 传球记录表(核心)
CREATE TABLE passes (
id INT PRIMARY KEY AUTO_INCREMENT,
match_id INT NOT NULL,
team_id INT NOT NULL,
player_id INT,
is_success TINYINT(1) NOT NULL DEFAULT 0, -- 1=成功 0=失败
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_match_team (match_id, team_id)
);
核心统计逻辑
传球成功率 = 成功传球数 ÷ 总传球数 × 100%
PHP 实现代码
数据库连接(PDO)
<?php
// db.php
$host = '127.0.0.1';
$db = 'football';
$user = 'root';
$pass = '';
$pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8mb4", $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
统计一场比赛中各队传球成功率
<?php
// stats_match.php
require 'db.php';
function getMatchPassStats(PDO $pdo, int $matchId): array
{
$sql = "
SELECT
t.id AS team_id,
t.name AS team_name,
COUNT(p.id) AS total_passes,
SUM(p.is_success) AS success_passes,
ROUND(SUM(p.is_success) / COUNT(p.id) * 100, 2) AS success_rate
FROM passes p
JOIN teams t ON t.id = p.team_id
WHERE p.match_id = :match_id
GROUP BY t.id, t.name
ORDER BY success_rate DESC
";
$stmt = $pdo->prepare($sql);
$stmt->execute([':match_id' => $matchId]);
return $stmt->fetchAll();
}
// 使用示例
$matchId = 1;
$stats = getMatchPassStats($pdo, $matchId);
echo "比赛 #{$matchId} 传球成功率统计:\n";
foreach ($stats as $row) {
printf(
"%s:%d/%d = %.2f%%\n",
$row['team_name'],
$row['success_passes'],
$row['total_passes'],
$row['success_rate']
);
}
// 判断哪队更高
if (count($stats) === 2) {
$winner = $stats[0]['success_rate'] > $stats[1]['success_rate']
? $stats[0]['team_name']
: ($stats[0]['success_rate'] < $stats[1]['success_rate']
? $stats[1]['team_name']
: '两队持平');
echo "\n传球成功率更高的是:{$winner}\n";
}
统计整个赛季 / 多场比赛的累计传球成功率
<?php
// stats_season.php
require 'db.php';
function getSeasonPassStats(PDO $pdo, ?string $startDate = null, ?string $endDate = null): array
{
$where = [];
$params = [];
if ($startDate) {
$where[] = 'm.match_date >= :start';
$params[':start'] = $startDate;
}
if ($endDate) {
$where[] = 'm.match_date <= :end';
$params[':end'] = $endDate;
}
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
$sql = "
SELECT
t.id AS team_id,
t.name AS team_name,
COUNT(p.id) AS total_passes,
SUM(p.is_success) AS success_passes,
ROUND(SUM(p.is_success) / COUNT(p.id) * 100, 2) AS success_rate
FROM passes p
JOIN teams t ON t.id = p.team_id
JOIN matches m ON m.id = p.match_id
{$whereSql}
GROUP BY t.id, t.name
HAVING total_passes > 0
ORDER BY success_rate DESC
";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
// 示例:统计 2024 赛季
$stats = getSeasonPassStats($pdo, '2024-01-01', '2024-12-31');
echo "2024 赛季各队传球成功率排行:\n";
echo str_repeat('-', 50) . "\n";
printf("%-20s %8s %8s %8s\n", '球队', '总传球', '成功', '成功率');
echo str_repeat('-', 50) . "\n";
foreach ($stats as $row) {
printf(
"%-20s %8d %8d %7.2f%%\n",
$row['team_name'],
$row['total_passes'],
$row['success_passes'],
$row['success_rate']
);
}
// 直接拿到第一名
if (!empty($stats)) {
echo "\n>>> 传球成功率最高:{$stats[0]['team_name']} ({$stats[0]['success_rate']}%)\n";
}
对比两支指定球队(常用于"哪队更高")
<?php
// compare_two_teams.php
require 'db.php';
function compareTeamsPassRate(PDO $pdo, int $teamA, int $teamB): array
{
$sql = "
SELECT
t.id, t.name,
COUNT(p.id) AS total,
SUM(p.is_success) AS success,
ROUND(SUM(p.is_success)/COUNT(p.id)*100, 2) AS rate
FROM passes p
JOIN teams t ON t.id = p.team_id
WHERE p.team_id IN (:a, :b)
GROUP BY t.id, t.name
";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':a', $teamA, PDO::PARAM_INT);
$stmt->bindValue(':b', $teamB, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll();
$map = array_column($rows, null, 'team_id');
$a = $map[$teamA] ?? ['name' => 'A', 'rate' => 0, 'total' => 0, 'success' => 0];
$b = $map[$teamB] ?? ['name' => 'B', 'rate' => 0, 'total' => 0, 'success' => 0];
$higher = $a['rate'] > $b['rate'] ? $a
: ($b['rate'] > $a['rate'] ? $b : null);
return ['team_a' => $a, 'team_b' => $b, 'higher' => $higher];
}
$result = compareTeamsPassRate($pdo, 1, 2);
echo "{$result['team_a']['name']}:{$result['team_a']['rate']}%\n";
echo "{$result['team_b']['name']}:{$result['team_b']['rate']}%\n";
echo $result['higher']
? "更高的是:{$result['higher']['name']}\n"
: "两队持平\n";
关键要点
| 要点 | 说明 |
|---|---|
| 分母口径 | 一般只算"尝试传球",需排除传中、长传单独统计口径(可按需过滤 pass_type) |
| 精度处理 | 用 ROUND(...,2),避免浮点误差展示;业务比较多用"成功数/总数"整数比较更稳 |
| 索引优化 | passes(match_id, team_id) 和 passes(team_id, is_success) 组合索引 |
| 大数据量 | 可加 passes_daily 汇总表(预聚合),避免每次全表扫描 |
| 主客场区分 | 如需分主客场,JOIN matches 后按 home_team_id/away_team_id 拆分 |
如果你没有数据库,纯数组版
<?php
function calcPassRate(array $teams): array
{
$result = [];
foreach ($teams as $name => $p) {
$total = $p['success'] + $p['fail'];
$rate = $total > 0 ? round($p['success'] / $total * 100, 2) : 0;
$result[$name] = compact('total', 'rate') + ['success' => $p['success']];
}
uasort($result, fn($a, $b) => $b['rate'] <=> $a['rate']);
return $result;
}
$teams = [
'A队' => ['success' => 320, 'fail' => 80],
'B队' => ['success' => 410, 'fail' => 90],
];
$rank = calcPassRate($teams);
print_r($rank);
echo "更高:" . array_key_first($rank) . "\n";
如果你能告诉我:
- 是否已有表结构(字段名不同)
- 想统计单场、赛季还是两队对比
- 是否需要区分主客场、传球类型(短传/长传/传中)
我可以帮你把代码改得更贴合你的项目。