【问题标题】:Self m:n Relation自 m:n 关系
【发布时间】:2011-08-24 12:22:56
【问题描述】:

我有几个人,一个人可以联系多个其他人,所以基本上“默认”表格是:

persons (id)
contacts (person1_id, person2_id)

使用此架构,我必须发出类似

的查询
SELECT   * 
FROM     contacts c
WHERE    ( person1_id = *id of person1* AND person2_id = *id of person2* )
         OR
         ( person1_id = *id of person2* AND person2_id = *id of person1* )

当我只插入一次这样的关系时得到两个人之间的关系。

处理这种情况的常见做法是什么?

  1. 插入一次数据并执行这样的 OR 查询
  2. 插入关系两次,这样person1_id = person1的id AND person2_id = person2的id就足够了
  3. 完全不同的方法?

假设:

  • m:n 表实际上包含其他数据,因此如果我为这两种方式创建关系,则必须复制数据
  • 这是应用程序的核心部分,大多数重要查询至少涉及一个子查询,用于确定是否存在此类关系

【问题讨论】:

  • 阅读一下 SQL 中的无向图,这就是您的 contacts 表所代表的内容。
  • 确保这确实符合您的要求,这意味着当 person1 联系 person2 时,这与 person2 联系 person1 的含义相同。那可能不是您真正想要的;我有时将区别描述为 twitter “follow” 模型与 facebook “friends” 模型。

标签: postgresql database-schema


【解决方案1】:

如果您编写插入逻辑使得person1_id < person2_id 对于所有行都为真,那么您可以编写

SELECT *
FROM contacts c
WHERE person1_id = min(*id_of_person_1*, *id_of_person_2*)
AND person2_id = max(*id_of_person_1*, *id_of_person_2*)

【讨论】:

  • 请注意,如果您必须执行“person1 的所有联系人”之类的查询,即使您执行上述建议(因为你不知道 person1 是给定关系的最小值还是最大值)
  • +1 上面 xzilla 的评论:如果问题不是“这两个人有关系吗”而是“谁与这个人有关系”,那么 min-max 属性是不够的.对于“谁是相关的”查询,我可能会将其写为 ...WHERE *id_of_person_1* IN (person1_id, person2_id) 只是为了使其更简洁并避免 AND/OR 优先级问题。
【解决方案2】:

为什么不在表之间使用 Join?

类似这样的:

SELECT *
FROM contact c INNER JOIN person p ON p.id = c.person1_id

您需要完成查询的位置和分组方式 =)

在这里看看结果将如何显示: http://www.w3schools.com/Sql/sql_join_inner.asp

问候,
埃尔卡斯

【讨论】:

  • 有完全相同的问题。我仍然需要做 p.id = c.person1_id 或 p.id = c.person2_id 等。
  • 右连接还是左连接呢?嗯,也许我不太明白你想要什么伴侣..你能解释得更好吗?
  • 给定:人员 1 - id:1,名称:foo 人员 2 - id:2,名称:bar。当 foo 联系 bar 时,会产生一个联系条目:person1_id: 1, person2_id: 2。当 bar 想要联系 foo 时,我必须查看联系表是否已经存在,为此,我必须发出这个查询:从联系人中选择 person1_id = 1 AND persond2_id = 2 OR person1_id = 2 AND person2_id = 1。我只想知道这种情况下的常见做法是什么,有这样的 OR 并不真正“感觉”正确。
  • 嗯..好的..我认为这是关系表对吧?试试这个:SELECT * FROM contacts c INNER JOIN person p ON p.id= c.person1_id INNER JOIN contacts c2 ON c2.person2_id = p.id;
  • 该查询不会返回任何内容,除非 foo 与 foo 有联系(因此它联系了自己)。
【解决方案3】:

试试这个伙伴 =)

SELECT c.person1_id as id_person_1, c.person2_id as id_person_2, p1.name as name_person_1, p2.name as name_person_2
FROM contact c
LEFT JOIN person p1 ON p1.id = c.person1_id
RIGHT JOIN person p2 ON p2.id = c.person2_id;

我不知道它是否会起作用..但试试看 mate =)

【讨论】:

  • 顺便说一句,如果我没记错的话,我前几次也遇到过同样的问题.. 获取 M-N 关系数据。你我之间的区别在于我有像这个成员这样的关系 - membre_has_group - group,而你有人员 - 联系人 - 人。检查他们给我的答案。它有很大帮助。 stackoverflow.com/questions/5487352/…
【解决方案4】:

“插入关系两次,这样 person1_id = id of person1 AND person2_id = id of person2 就足够了”

这就是我个人的做法。它允许处理 A 有 B 的联系方式但不能反过来的情况(例如,一个女孩在酒吧里给一个男人她的电话号码,当她走出去时说“给我打电话”)。它还使查询更简单。

【讨论】:

    猜你喜欢
    • 2014-08-30
    • 2017-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    相关资源
    最近更新 更多