【发布时间】:2020-05-05 13:36:01
【问题描述】:
我很难在 Oracle 中创建一个函数来确定 2 种交配动物是否会产生近亲繁殖。 函数需要3个参数:男性ID、女性ID和要查看的深度。
起初我认为我应该使用具有如下结构的表中的数据创建两个谱系:
TABLE animal
+-----+---------+--------+
| ID | SIRE_ID | DAM_ID |
+-----+---------+--------+
| 111 | 112 | 212 |
| 112 | 113 | 213 |
| 212 | 116 | 216 |
+-----+---------+--------+
(不完全相关,但对于这个和未来的例子,我使用 ID-s 作为 1?? 是男性和 2?? 是女性。) 为此,我应该使用深度参数 - 可能是递归的。
这是我目前所拥有的:
function animal_pedigree (p_id number,
p_max_pedigree_level number,
p_pedigree_level number := 0,
p_position varchar2 := '') return animal_ancestors_table
pipelined
is
v_sire_id number;
v_dam_id number;
v_row animal_ancestor;
begin
v_row.id := p_id;
v_row.pedigree_level := p_pedigree_level;
v_row.position := p_position;
pipe row (v_row);
if p_pedigree_level < p_max_pedigree_level then
select sire_id, dam_id
into v_sire_id, v_dam_id
from arc.animal
where id = p_id;
if v_sire_id is not null then
for rec in (select id, pedigree_level, position
from table(animal_pedigree (v_sire_id, p_max_pedigree_level, p_pedigree_level+1, p_position || 's'))) loop
v_row.id := rec.id;
v_row.pedigree_level := rec.pedigree_level;
v_row.position := rec.position;
pipe row (v_row);
end loop;
end if;
if v_dam_id is not null then
for rec in (select id, pedigree_level, position
from table(animal_pedigree (v_dam_id, p_max_pedigree_level, p_pedigree_level+1, p_position || 'd'))) loop
v_row.id := rec.id;
v_row.pedigree_level := rec.pedigree_level;
v_row.position := rec.position;
pipe row (v_row);
end loop;
end if;
end if;
return;
end;
接下来是我最棘手的部分:比较谱系以找到匹配的 ID(并记住找到匹配的深度)。
最终我想返回发现近亲繁殖的最小深度,或者返回 0(如果没有发现)。
注意!我只想比较两个谱系,而不是比较一个内部的 ID。 (如果已经存在近亲繁殖,我希望它被忽略,只对新形成的近亲繁殖感兴趣。)
为了进一步说明,我添加了 3 个示例。 标有 *(星号)的匹配项。
示例 1:
男性血统
Depth 1 2 3
|--114
|--113--|
| |--214
|--112--|
| | |--115
| |--213--|
| |--215
111--|
| |--117
| |--116--|
| | |--217
|--212--|
| |--118
|--216--|
|--218
女性血统
Depth 1 2 3
|--124
|--123--|
| |--224
|--122--|
| | |--125
| |--223--|
| |--225
211--|
| |--127
| |--126--|
| | |--227
|--222--|
| |--128
|--226--|
|--228
[RETURN 0] 未找到相同的 ID
示例 2:
男性血统
Depth 1 2 3
|--114*
|--113--|
| |--214
|--112--|
| | |--115
| |--213--|
| |--215
111--|
| |--117
| |--116--|
| | |--217
|--212--|
| |--114*
|--216--|
|--218
女性血统
Depth 1 2 3
|--124
|--123--|
| |--224
|--122--|
| | |--125
| |--223--|
| |--225
211--|
| |--127
| |--126--|
| | |--227
|--222--|
| |--128
|--226--|
|--228
[RETURN 0] 匹配的 ID-s 都在男性谱系中找到。忽略。
示例 3:
男性血统
Depth 1 2 3
|--114*
|--113--|
| |--214
|--112--|
| | |--115
| |--213--|
| |--215
111--|
| |--117
| |--116--|
| | |--217
|--212--|
| |--118
|--216--|
|--218
女性血统
Depth 1 2 3
|--124
|--123--|
| |--224
|--122--|
| | |--125
| |--223--|
| |--225
211--|
| |--127
| |--114*-|
| | |--227
|--222--|
| |--128
|--226--|
|--228
[RETURN 2] 在男性谱系的深度 3 和女性谱系的深度 2 中找到匹配 ID
【问题讨论】:
-
您的示例有助于理解问题。为了帮助我们所有人测试我们的暂定解决方案,添加
create table as select ...语句以在实际表中重现示例数据也会有所帮助。 -
您可以使用递归 CTE 找到结果。它应该比程序简单得多。
-
抱歉,忘了说我正在运行 oracle 10(g)