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

如何编写循环或foreach遍历获取马匹谱系6级亲本数据?

解决6级马匹谱系的查询问题

嘿,我正好做过类似的谱系查询需求,结合你的MySQL表结构,给你几个实用的方案:

方案1:MySQL 8.0+ 递归CTE(最简洁高效)

如果你的MySQL版本是8.0及以上,递归公共表表达式(CTE)是最优解,能一次性查出所有6级亲本,还能清晰标记层级:

WITH RECURSIVE horse_ancestry AS (
    -- 锚点:初始马匹(horse_id=1),层级为0
    SELECT 
        horse_id, 
        horse_name, 
        horse_sire, 
        horse_dam, 
        0 AS level
    FROM horses 
    WHERE horse_id = 1

    UNION ALL

    -- 递归部分:查询当前层级马匹的父本和母本,层级+1
    SELECT 
        h.horse_id, 
        h.horse_name, 
        h.horse_sire, 
        h.horse_dam, 
        ha.level + 1 AS level
    FROM horse_ancestry ha
    LEFT JOIN horses h ON h.horse_id = ha.horse_sire OR h.horse_id = ha.horse_dam
    WHERE ha.level < 6  -- 限制到6级
      AND h.horse_id IS NOT NULL  -- 过滤无亲本的情况
)
SELECT * FROM horse_ancestry ORDER BY level, horse_id;

说明:

  • 锚点部分先获取起点马匹(level=0)
  • 递归部分每次关联当前马匹的父本(horse_sire)和母本(horse_dam),层级自增1
  • level < 6确保只查到第6级(level从0开始,0是自身,1是一级亲本,直到6是第六级)
  • 可以根据需求调整SELECT字段,比如只返回每级的名称和ID

方案2:MySQL 5.x 多次LEFT JOIN(兼容旧版本)

如果你的MySQL版本不支持CTE,只能用多次LEFT JOIN来硬关联每一级的亲本,虽然代码长但实用:

SELECT
    -- 自身(第0级)
    h0.horse_id AS id_0, h0.horse_name AS name_0,
    -- 第1级亲本
    h1_sire.horse_id AS id_1_sire, h1_sire.horse_name AS name_1_sire,
    h1_dam.horse_id AS id_1_dam, h1_dam.horse_name AS name_1_dam,
    -- 第2级亲本
    h2_sire_sire.horse_id AS id_2_sire_sire, h2_sire_sire.horse_name AS name_2_sire_sire,
    h2_sire_dam.horse_id AS id_2_sire_dam, h2_sire_dam.horse_name AS name_2_sire_dam,
    h2_dam_sire.horse_id AS id_2_dam_sire, h2_dam_sire.horse_name AS name_2_dam_sire,
    h2_dam_dam.horse_id AS id_2_dam_dam, h2_dam_dam.horse_name AS name_2_dam_dam,
    -- 以此类推,直到第6级...(这里只写了2级,你可以按相同逻辑扩展到6级)
FROM horses h0
-- 第1级
LEFT JOIN horses h1_sire ON h0.horse_sire = h1_sire.horse_id
LEFT JOIN horses h1_dam ON h0.horse_dam = h1_dam.horse_id
-- 第2级
LEFT JOIN horses h2_sire_sire ON h1_sire.horse_sire = h2_sire_sire.horse_id
LEFT JOIN horses h2_sire_dam ON h1_sire.horse_dam = h2_sire_dam.horse_id
LEFT JOIN horses h2_dam_sire ON h1_dam.horse_sire = h2_dam_sire.horse_id
LEFT JOIN horses h2_dam_dam ON h1_dam.horse_dam = h2_dam_dam.horse_id
-- 继续添加第3到第6级的LEFT JOIN...
WHERE h0.horse_id = 1;

说明:

  • 每一级都要分别关联父本的父、父本的母、母本的父、母本的母
  • 虽然代码冗长,但适合不支持递归的旧版本MySQL
  • 无亲本的字段会显示为NULL,你可以用COALESCE替换为默认值(比如'无记录')

方案3:应用层循环遍历(灵活可控)

如果不想在数据库层做复杂查询,也可以在应用层(比如PHP、Python)用循环/foreach来逐层获取亲本,步骤如下:

  1. 初始化一个数组,存入起点马匹(horse_id=1)
  2. 循环6次,每次处理当前层级的所有马匹ID:
    • 批量查询这些ID对应的horse_sire和horse_dam
    • 收集所有非NULL的亲本ID,作为下一层级的处理对象
    • 记录每一级的亲本数据
  3. 最后整理所有层级的数据返回

以PHP为例的伪代码:

$currentHorseIds = [1];
$ancestry = [];

for ($level = 1; $level <= 6; $level++) {
    // 批量查询当前所有马匹的亲本
    $placeholders = implode(',', array_fill(0, count($currentHorseIds), '?'));
    $stmt = $pdo->prepare("SELECT horse_id, horse_sire, horse_dam FROM horses WHERE horse_id IN ($placeholders)");
    $stmt->execute($currentHorseIds);
    $horses = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $nextHorseIds = [];
    $levelData = [];

    foreach ($horses as $horse) {
        // 处理父本
        if ($horse['horse_sire']) {
            $sire = $pdo->query("SELECT horse_id, horse_name FROM horses WHERE horse_id = {$horse['horse_sire']}")->fetch(PDO::FETCH_ASSOC);
            $levelData[] = ['level' => $level, 'type' => 'sire', ...$sire];
            $nextHorseIds[] = $horse['horse_sire'];
        }
        // 处理母本
        if ($horse['horse_dam']) {
            $dam = $pdo->query("SELECT horse_id, horse_name FROM horses WHERE horse_id = {$horse['horse_dam']}")->fetch(PDO::FETCH_ASSOC);
            $levelData[] = ['level' => $level, 'type' => 'dam', ...$dam];
            $nextHorseIds[] = $horse['horse_dam'];
        }
    }

    $ancestry[$level] = $levelData;
    $currentHorseIds = array_unique($nextHorseIds);

    // 如果没有下一级亲本,提前终止循环
    if (empty($currentHorseIds)) break;
}

// 输出结果
print_r($ancestry);

说明:

  • 用批量查询替代逐个查询,避免N+1性能问题
  • 可以灵活控制每一级的数据处理,比如添加额外的业务逻辑
  • 适合需要对每级数据做自定义处理的场景

注意事项

  • 你的表已经给horse_sire和horse_dam建了索引,这很重要,能大幅提升查询性能
  • 要处理horse_sire或horse_dam为NULL的情况(有些马匹可能没有记录亲本)
  • 递归查询时要加层级限制,避免无限循环(虽然外键约束不会出现循环,但数据异常时可能发生)

内容的提问来源于stack exchange,提问作者Salah Eddine Abida

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:37:54