近交免疫数据库结构


Inbreeding-immune database structure

我有一个需要"简单"家谱的应用程序。我希望能够执行查询,为我提供整个家庭的数据,该家庭中的一个成员只提供一个id。我之所以说简单,是因为它不需要考虑收养或任何其他模糊之处。应用程序的要求如下:

  • 如果两个人来自同一个基因系,他们将无法繁殖
  • 需要允许添加新的家族(没有以前家族的新人)
  • 需要能够通过查询分别拉取兄弟姐妹、父母

我很难为数据库找到合适的结构。到目前为止,我已经想出了两个解决方案,但它们不是很可靠,可能很快就会失控。

解决方案1包括在人员表上放置一个family_ids字段,并存储一个唯一的族ID列表。每次两个人繁殖时,都会对列表进行检查,以确保没有ID匹配,如果所有项都检查出来,则会合并这两个列表,并将其设置为孩子的family_ids字段。

示例:

Father (family_ids: (null)) breeds with Mother (family_ids: (213, 519)) ->
Child (family_ids: (213, 519)) breeds with Random Person (family_ids: (813, 712, 122, 767)) ->
Grandchild (family_ids: (213, 519, 813, 712, 122, 767))

等等。。。我看到的问题是,随着时间的推移,列表变得不合理地大

解决方案2使用cakepp的关联来声明:

public $belongsTo = array(
    'Father' => array(
        'className' => 'User',
        'foreignKey' => 'father_id'
    ),
    'Mother' => array(
        'className' => 'User',
        'foreignKey' => 'mother_id'
    )
);

现在,将递归设置为2将获取母亲和父亲的结果,以及他们的母亲和父亲,依此类推。这个路由的问题是数据在嵌套数组中,我不确定如何有效地处理代码。

如果有人能引导我朝着最有效的方向去处理我想要实现的目标,那将是非常有帮助的。我们非常感谢您的帮助,我很乐意回答任何人的问题。非常感谢。

在SQL(更准确地说,是RDBS)中,我会使用以下解决方案:

1) 创建一个包含以下字段的表peopleidnamefather_idmother_id。第一个是一个典型的主键列,father_id和mother_id指的是该列,但可以NULL(以允许添加新的族线)。

2) 创建一个包含以下字段的表relatives——person_idancestor_id。两者都不为NULL,都形成一个复合主键,对于person.id,两者都是FK。

就这样。不,真的!)现在考虑您的任务:

  • 添加一些没有家族关系的人

这也是非常可行的:INSERT INTO people (name) VALUES ('some_name')。诀窍是将与这个新人相关的另一个插入到亲属中:INSERT INTO relatives VALUES (%new_person_id%, %new_person_id%)

那是干什么的?考虑一下最常见的任务:添加一个实际上已经在你的表中列出了父亲和母亲的人。使用这种结构,它可以简单地完成(在将相应的记录插入到people中,并得到该person_id之后)。。。

INSERT INTO relatives 
    SELECT %new_person_id%, ancestor_id 
      FROM relatives 
     WHERE person_id IN (%father_id%, %mother_id%);
INSERT INTO relatives VALUES (%new_person_id%, %new_person_id%);
  • 如果任何两个人来自同一个基因系,他们将无法繁殖

使用上面描述的结构非常简单:您必须在relatives中查找两条在ancestor_id字段中具有相同值的记录。例如:

    SELECT COUNT(*) 
      FROM relatives ra 
INNER JOIN relatives rb ON ra.ancestor_id = rb.ancestor_id
     WHERE ra.person_id = %person_a_id%
       AND rb.person_id = %person_b_id%

在这个结构中寻找所有的祖先和孩子是很容易的;但我仍然更喜欢去规范化的方法(即,将parent_id和mother_id存储在第一个表中)来加快直接父/子的查找速度——实际上,只需第一个表就可以完成。

下面是一个正在工作的(尽管有点短)SQLFiddle示例,以更实用的颜色显示了这一点。)