Чтобы предотвратить злоупотребление вашей базой данных итеративными вызовами, ВЫБЕРИТЕ всю таблицу всего один раз и позвольте php выполнить всю рекурсивную работу с набором результатов.
AMENDMENT : С момента сбора ~100 000 строк - это слишком тяжело, вот альтернативный совет ... Вместо того, чтобы совершать до 31 отдельного обращения к базе данных в рамках рекурсивного процесса, я рекомендую вам создать отфильтрованный массив на основе до 5 обращений к базе данных..
Следующий фрагмент НЕ протестирован:
$generation = 1;
$needles = [1];
$animals = [];
while ($needles && $generation < 6) {
$sth = $db->prepare("SELECT * FROM animals WHERE akc_reg_num IN (" . implode(',', array_fill(0, count($needles), '?')) . ")");
$sth->execute($needles);
if ($results = $sth->fetchAll(\PDO::FETCH_ASSOC)) {
$needles = array_filter(array_merge(array_column($results, 'akc_parent_sire'), array_column($results, 'akc_parent_dam')));
$animals[] = array_merge($animal, $results);
} else {
$needles = null;
}
++$generation;
}
// $animals is ready to pass to the php recursion
Из набора результатов $animals
, подобного следующему:
$animals = [
['id' => 1, 'akc_reg_num' => 1, 'akc_parent_sire' => 2, 'akc_parent_dam' => 3],
['id' => 2, 'akc_reg_num' => 2, 'akc_parent_sire' => 5, 'akc_parent_dam' => 6],
['id' => 3, 'akc_reg_num' => 3, 'akc_parent_sire' => 9, 'akc_parent_dam' => 0],
['id' => 4, 'akc_reg_num' => 5, 'akc_parent_sire' => 0, 'akc_parent_dam' => 0],
['id' => 5, 'akc_reg_num' => 6, 'akc_parent_sire' => 7, 'akc_parent_dam' => 8],
['id' => 6, 'akc_reg_num' => 7, 'akc_parent_sire' => 0, 'akc_parent_dam' => 0],
['id' => 7, 'akc_reg_num' => 8, 'akc_parent_sire' => 0, 'akc_parent_dam' => 0],
['id' => 8, 'akc_reg_num' => 9, 'akc_parent_sire' => 10, 'akc_parent_dam' => 11],
['id' => 9, 'akc_reg_num' => 10, 'akc_parent_sire' => 0, 'akc_parent_dam' => 0],
['id' => 10, 'akc_reg_num' => 11, 'akc_parent_sire' => 12, 'akc_parent_dam' => 0],
['id' => 11, 'akc_reg_num' => 12, 'akc_parent_sire' => 0, 'akc_parent_dam' => 0]
];
Подробные задачи:
- Найдите в вашем массиве строку целевого
akc_reg_num
, затем удалите эту строку из "стога сена", чтобы предотвратить возможность бесконечной рекурсии, затем прервите цикл поиска для достижения максимальной эффективности - Если естьнет соответствующего akc_reg_num в стоге сена, вернуть пустой массив
- Если есть соответствующий akc_reg_num, зациклить стог сена и восстановить все найденные родители.Я отфильтровываю «deadends», чтобы массив результатов был маленьким и чистым.
- Если оба родителя найдены в данном поколении, прервите цикл, чтобы предотвратить ненужные итерации.
- Рекурсия должна продолжатьсяпока число поколений не превысит 4, или не останется больше родителей для сбора.
Код: ( Демо )
function buildPedigree($haystack, $akc_reg_num, $generation = 0) {
++$generation;
foreach ($haystack as $index => $row) {
if ($row['akc_reg_num'] == $akc_reg_num) {
$result = ['sire' => $row['akc_parent_sire'], 'dam' => $row['akc_parent_dam']];
unset($haystack[$index]); // reduce the haystack to improve efficiency and avoid infinite loop
break; // stop searching
}
}
if (!isset($result)) {
return []; // $akc_reg_num not found
}
foreach ($haystack as $row) {
if ($row['akc_reg_num'] == $result['sire']) {
$result['sire_parents'] = array_filter(buildPedigree($haystack, $row['akc_reg_num'], $generation)); // recurse and purge empty parent arrays
if (array_key_exists('dam_parents', $result)) {
break; // both parents found in generation, stop this loop
}
} elseif ($row['akc_reg_num'] == $result['dam']) {
$result['dam_parents'] = array_filter(buildPedigree($haystack, $row['akc_reg_num'], $generation)); // recurse and purge empty parent arrays
if (array_key_exists('sire_parents', $result)) {
break; // both parents found in generation, stop this loop
}
}
}
return $generation <= 4 ? $result : [];
}
var_export(buildPedigree($animals, 1));
Вывод:
array (
'sire' => 2,
'dam' => 3,
'sire_parents' => array (
'sire' => 5,
'dam' => 6,
'dam_parents' => array (
'sire' => 7,
'dam' => 8,
),
),
'dam_parents' => array (
'sire' => 9,
'sire_parents' => array (
'sire' => 10,
'dam' => 11,
'dam_parents' => array (
'sire' => 12,
),
),
),
)