You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多表连接时Goals表引发Gamelog行重复的技术解决方案问询

多表连接后赛事信息重复的解决方法

问题背景

连接gamelog(赛事记录表)、teams(球队表)和goals(进球记录表)时,因goals表单场赛事对应多条记录,导致赛事对阵信息重复显示,重复次数等于该场进球数。

单独连接gamelog和teams能正常显示单场对阵:

$sql = "SELECT gamelog.game_number, gamelog.home_team_id, gamelog.away_team_id, 
t1.name AS hometeam, t2.name AS awayteam
FROM gamelog
JOIN teams AS t1 ON gamelog.home_team_id=t1.id
JOIN teams AS t2 ON gamelog.away_team_id=t2.id";

$statement = $pdo->query($sql);
$results = $statement->fetchAll();

<?php foreach($results as $result) { ?>
  Game Number: <?= $result['game_number']; ?>
   
    <?= $result['hometeam'].' VERSUS '.$result['awayteam']; ?>
    
    
<?php } ?>

但加入goals表后,赛事信息重复:

$sql = "SELECT gamelog.game_number, gamelog.home_team_id, gamelog.away_team_id, 
t1.name AS hometeam, t2.name AS awayteam,
goals.game_number_id, goals.team_id_goal
FROM gamelog
JOIN teams AS t1 ON gamelog.home_team_id=t1.id
JOIN teams AS t2 ON gamelog.away_team_id=t2.id
JOIN goals ON gamelog.game_number = goals.game_number_id";

$statement = $pdo->query($sql);
$results = $statement->fetchAll();

<?php foreach($results as $result) { ?>
        Game Number: <?= $result['game_number']; ?>
        <br>
        <?= $result['hometeam'].' VERSUS '.$result['awayteam']; ?>
        <br>
        Which team scored the goals: <?= $result['team_id_goal']; ?>
        <br>
        
<?php } ?>

期望输出:每场赛事仅显示一次对阵信息,随后列出该场所有进球记录。尝试过GROUP BY但语法错误,双查询又重复输出进球,寻求解决方法。

附查询返回的$results数组:

array(8) { 
  [0]=> array(11) { ["game_number"]=> int(1) ["home_team_id"]=> int(1) ["away_team_id"]=> int(2) ["home_score"]=> int(2) ["away_score"]=> int(1) ["hometeam"]=> string(3) "MTL" ["awayteam"]=> string(3) "BOS" ["homelogo"]=> string(12) "habs-svg.svg" ["awaylogo"]=> string(14) "bruins-svg.svg" ["game_number_id"]=> int(1) ["team_id_goal"]=> int(1) } 
  [1]=> array(11) { ["game_number"]=> int(1) ["home_team_id"]=> int(1) ["away_team_id"]=> int(2) ["home_score"]=> int(2) ["away_score"]=> int(1) ["hometeam"]=> string(3) "MTL" ["awayteam"]=> string(3) "BOS" ["homelogo"]=> string(12) "habs-svg.svg" ["awaylogo"]=> string(14) "bruins-svg.svg" ["game_number_id"]=> int(1) ["team_id_goal"]=> int(1) } 
  [2]=> array(11) { ["game_number"]=> int(1) ["home_team_id"]=> int(1) ["away_team_id"]=> int(2) ["home_score"]=> int(2) ["away_score"]=> int(1) ["hometeam"]=> string(3) "MTL" ["awayteam"]=> string(3) "BOS" ["homelogo"]=> string(12) "habs-svg.svg" ["awaylogo"]=> string(14) "bruins-svg.svg" ["game_number_id"]=> int(1) ["team_id_goal"]=> int(2) } 
  [3]=> array(11) { ["game_number"]=> int(2) ["home_team_id"]=> int(2) ["away_team_id"]=> int(1) ["home_score"]=> int(3) ["away_score"]=> int(2) ["hometeam"]=> string(3) "BOS" ["awayteam"]=> string(3) "MTL" ["homelogo"]=> string(14) "bruins-svg.svg" ["awaylogo"]=> string(12) "habs-svg.svg" ["game_number_id"]=> int(2) ["team_id_goal"]=> int(2) } 
  [4]=> array(11) { ["game_number"]=> int(2) ["home_team_id"]=> int(2) ["away_team_id"]=> int(1) ["home_score"]=> int(3) ["away_score"]=> int(2) ["hometeam"]=> string(3) "BOS" ["awayteam"]=> string(3) "MTL" ["homelogo"]=> string(14) "bruins-svg.svg" ["awaylogo"]=> string(12) "habs-svg.svg" ["game_number_id"]=> int(2) ["team_id_goal"]=> int(2) } 
  [5]=> array(11) { ["game_number"]=> int(2) ["home_team_id"]=> int(2) ["away_team_id"]=> int(1) ["home_score"]=> int(3) ["away_score"]=> int(2) ["hometeam"]=> string(3) "BOS" ["awayteam"]=> string(3) "MTL" ["homelogo"]=> string(14) "bruins-svg.svg" ["awaylogo"]=> string(12) "habs-svg.svg" ["game_number_id"]=> int(2) ["team_id_goal"]=> int(2) } 
  [6]=> array(11) { ["game_number"]=> int(2) ["home_team_id"]=> int(2) ["away_team_id"]=> int(1) ["home_score"]=> int(3) ["away_score"]=> int(2) ["hometeam"]=> string(3) "BOS" ["awayteam"]=> string(3) "MTL" ["homelogo"]=> string(14) "bruins-svg.svg" ["awaylogo"]=> string(12) "habs-svg.svg" ["game_number_id"]=> int(2) ["team_id_goal"]=> int(1) } 
  [7]=> array(11) { ["game_number"]=> int(2) ["home_team_id"]=> int(2) ["away_team_id"]=> int(1) ["home_score"]=> int(3) ["away_score"]=> int(2) ["hometeam"]=> string(3) "BOS" ["awayteam"]=> string(3) "MTL" ["homelogo"]=> string(14) "bruins-svg.svg" ["awaylogo"]=> string(12) "habs-svg.svg" ["game_number_id"]=> int(2) ["team_id_goal"]=> int(1) } 
}

解决方案1:前端循环优化

在PHP循环时,先将结果按赛事ID分组,只在赛事ID变化时输出对阵信息,之后统一输出该场所有进球。

代码示例:

// 按赛事ID分组整理数据
$games = [];
foreach ($results as $row) {
    $gameId = $row['game_number'];
    if (!isset($games[$gameId])) {
        // 初始化赛事基础信息
        $games[$gameId] = [
            'game_number' => $row['game_number'],
            'hometeam' => $row['hometeam'],
            'awayteam' => $row['awayteam'],
            'home_score' => $row['home_score'],
            'away_score' => $row['away_score'],
            'goals' => []
        ];
    }
    // 追加进球记录
    $games[$gameId]['goals'][] = $row['team_id_goal'];
}

// 遍历分组后的数据输出
foreach ($games as $game) {
?>
    <div class="game-card">
        Game Number: <?= $game['game_number']; ?><br>
        <?= $game['hometeam'] . ' VS ' . $game['awayteam']; ?><br>
        Final Score: <?= $game['home_score'] . ' - ' . $game['away_score']; ?><br>
        <strong>Goal History:</strong><br>
        <?php foreach ($game['goals'] as $teamId) { ?>
            - Team ID <?= $teamId; ?> scored<br>
        <?php } ?>
    </div>
    <hr>
<?php
}

解决方案2:SQL查询优化(聚合进球信息)

使用GROUP_CONCAT将单场赛事的所有进球球队ID合并为一个字符串,让每条赛事记录仅出现一次,前端再拆分字符串展示进球。

SQL查询语句:

SELECT 
    gamelog.game_number,
    gamelog.home_team_id,
    gamelog.away_team_id,
    gamelog.home_score,
    gamelog.away_score,
    t1.name AS hometeam,
    t2.name AS awayteam,
    t1.logo AS homelogo,
    t2.logo AS awaylogo,
    GROUP_CONCAT(goals.team_id_goal SEPARATOR ',') AS goal_teams
FROM gamelog
JOIN teams AS t1 ON gamelog.home_team_id = t1.id
JOIN teams AS t2 ON gamelog.away_team_id = t2.id
LEFT JOIN goals ON gamelog.game_number = goals.game_number_id
GROUP BY gamelog.game_number, gamelog.home_team_id, gamelog.away_team_id, gamelog.home_score, gamelog.away_score, t1.name, t2.name, t1.logo, t2.logo

前端输出代码:

$statement = $pdo->query($sql);
$results = $statement->fetchAll();

foreach ($results as $game) {
?>
    <div class="game-card">
        Game Number: <?= $game['game_number']; ?><br>
        <?= $game['hometeam'] . ' VS ' . $game['awayteam']; ?><br>
        Final Score: <?= $game['home_score'] . ' - ' . $game['away_score']; ?><br>
        <strong>Goal History:</strong><br>
        <?php 
        $goalTeams = explode(',', $game['goal_teams'] ?? '');
        foreach ($goalTeams as $teamId) {
            if (!empty($teamId)) {
        ?>
                - Team ID <?= $teamId; ?> scored<br>
        <?php 
            }
        }
        ?>
    </div>
    <hr>
<?php
}

注意事项

  • 使用GROUP_CONCAT时,需确保MySQL的group_concat_max_len参数足够大,避免截断长字符串;若要保留进球顺序,可添加ORDER BY,例如GROUP_CONCAT(goals.team_id_goal ORDER BY goals.id SEPARATOR ',')。
  • 用LEFT JOIN替代JOIN,确保无进球的赛事也能正常显示。

内容的提问来源于stack exchange,提问作者JahIsGucci

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 02:14:54