近亲繁殖 - 免疫数据库结构

时间:2012-07-07 04:23:09

标签: php mysql cakephp database-design

我有一个需要“简单”家谱的应用程序。我希望能够执行查询,这些查询将为整个家庭提供数据,给出一个来自该家庭成员的id。我说的很简单,因为它不需要考虑采用或任何其他晦涩。申请的要求如下:

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

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

解决方案1涉及在people表上放置family_ids字段并存储唯一的family 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使用cakephp的关联来声明:

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

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

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

1 个答案:

答案 0 :(得分:2)

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

1)创建一个包含以下字段的表people - idnamefather_idmother_id。第一个是典型的主键列,father_id和mother_id引用此列但是为NULLable(允许添加新的族行)。

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%

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

这是一个工作(尽管有点短)SQL Fiddle示例,以更实用的颜色显示这一点。 )