我有一个狗的数据库。每只狗都有一个父亲和一个水坝父母。我不是 由于phpmyadmin和MariaDB 10.0出现问题,因此可以使用CTE。
表为animal
我正在使用的列是:
id
,akc_reg_num
,akc_parent_sire
,akc_parent_dam
我试图像加载子类别一样只获得一代,但是当有两个父母时,这只是一侧。
我已经尝试过这种解决方案,但是无法让每个兄弟姐妹的两个父母缠住头。 How do I select only one generation of a hierarchical tree using an table parent child relation with SQL?
示例表
CREATE TABLE `animal` (
`id` INT(11) NOT NULL AUTO_INCREMENT ,
`akc_reg_num` VARCHAR(20) NOT NULL ,
`akc_parent_sire` VARCHAR(20) NOT NULL ,
`akc_parent_dam` VARCHAR(20) NOT NULL ,
PRIMARY KEY (`id`)
) ENGINE = MyISAM;
INSERT INTO `animal` (`id`, `akc_reg_num`, `akc_parent_sire`, `akc_parent_dam`) VALUES
(NULL, '1', '2', '3'),
(NULL, '2', '5', '6'),
(NULL, '3', '9', ''),
(NULL, '5', '', ''),
(NULL, '6', '7', '8'),
(NULL, '7', '', ''),
(NULL, '8', '', ''),
(NULL, '9', '10', '11'),
(NULL, '10', '', ''),
(NULL, '11', '12', ''),
(NULL, '12', '', '');
代码:
include_once("db_conx.php");
function getPedigree($node) {
// look up the parent of this node
$sql = 'SELECT akc_parent_sire, akc_parent_dam FROM animals WHERE akc_reg_num="'.$node.'";';
$query = $db->prepare($sql);
$query->execute();
$path = array();
while($row=$query->fetch(PDO::FETCH_ASSOC)){
if ($row['akc_parent_sire']!='') {
$path[] = $row['akc_parent_sire'];
echo $row['akc_parent_sire'];
$path = array_merge(getPedigree($row['akc_parent_sire']), $path);
}
if ($row['akc_parent_dam']!='') {
$path[] = $row['akc_parent_dam'];
echo $row['akc_parent_dam'];
$path = array_merge(getPedigree($row['akc_parent_dam']), $path);
}
}
return $path;
}
print_r(getPedigree('vvv'));
我需要遍历每一代,以便返回一个json数组,然后使用javascript将结果绑定到DOM元素。我只需要查询4代,但是我担心的是CPU周期的开销。一旦我在数据库中有了几十万只动物,这个查询的效率如何?
答案 0 :(得分:1)
为防止重复调用滥用数据库,请一次选择整个表,然后让php对结果集执行所有递归工作。
修改:由于收集〜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
的行,然后从“干草堆”中删除该行以防止无限递归的发生,然后中断搜索循环以获取最佳效率代码:(Demo)
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,
),
),
),
)