【问题标题】:De-duplicating many-to-many relationships in MySQL lookup table在 MySQL 查找表中删除重复的多对多关系
【发布时间】:2015-10-15 06:05:44
【问题描述】:

我继承了一个数据库,其中包含一个查找表以查找与给定专利相关的其他专利。

看起来像

╔════╦═══════════╦════════════╗
║ id ║ patent_id ║ related_id ║
╠════╬═══════════╬════════════╣
║ 1  ║     1     ║     2      ║
║ 2  ║     1     ║     3      ║
║ 3  ║     2     ║     1      ║
║ 4  ║     2     ║     3      ║
║ 5  ║     3     ║     2      ║
╚════╩═══════════╩════════════╝

我想过滤掉互惠关系。 1->2 和 2->1 对于我的目的是相同的,所以我只想要 1->2。

我不需要在表格中进行编辑,我只需要一个查询来返回唯一关系列表,虽然我确信这很简单,但我一直在用头敲键盘太长。

【问题讨论】:

  • 啊,是的,谢谢@TimBiegeleisen。我搜索但不知何故错过了那个。明天我会试试这个答案,看看它是否有效。
  • 使用这个SELECT DISTINCT LEAST(patent_id, related_id), GREATEST(patent_id, related_id) FROM mytable
  • 这最终成为我所需要的最简单的答案。

标签: mysql many-to-many unique


【解决方案1】:

这是一个您可以尝试使用的巧妙查询。一般的策略是识别不需要的重复记录,然后从整个集合中减去它们。

SELECT t.id, t.patent_id, t.related_id
FROM t LEFT JOIN
(
    SELECT t1.patent_id AS t1_patent_id, t1.related_id AS t1_related_id
    FROM t t1 LEFT JOIN t t2
    ON t1.related_id = t2.patent_id
    WHERE t1.patent_id = t2.related_id AND t1.patent_id > t1.related_id
) t3
ON t.patent_id = t3.t1_patent_id AND t.related_id = t3.t1_related_id
WHERE t3.t1_patent_id IS NULL

这是此查询生成的内部临时表。您可以说服自己,通过应用WHERE 子句中的逻辑,您将选择正确的记录。非重复记录以t1.patent_id != t2.related_id 为特征,所有这些记录都被保留。对于重复项 (t1.patent_id = t2.related_id),从每对重复项中选择的记录是 patent_id related_id,正如您在问题中所要求的那样。

╔════╦══════════════╦═══════════════╦══════════════╦═══════════════╗  
║ id ║ t1.patent_id ║ t1.related_id ║ t2.patent_id ║ t2.related_id ║
╠════╬══════════════╬═══════════════╬══════════════╬═══════════════╣
║ 1  ║      1       ║       2       ║      2       ║       1       ║ * duplicate
║ 1  ║      1       ║       2       ║      2       ║       3       ║
║ 2  ║      1       ║       3       ║      3       ║       2       ║
║ 3  ║      2       ║       1       ║      1       ║       2       ║ * duplicate
║ 3  ║      2       ║       1       ║      1       ║       3       ║
║ 4  ║      2       ║       3       ║      3       ║       2       ║ * duplicate
║ 5  ║      3       ║       2       ║      2       ║       1       ║
║ 5  ║      3       ║       2       ║      2       ║       3       ║ * duplicate
╚════╩══════════════╩═══════════════╩══════════════╩═══════════════╝

单击下面的链接查看此查询的运行示例。

SQLFiddle

【讨论】:

【解决方案2】:

试试类似的东西

select distinct * from
(select patient_id, related_id from TABLENAME
 union
select related_id, patient_id from TABLENAME
);

好吧,你说得对,上面的方法行不通。试试

select patient_id, related_id from TABLENAME p1
where p1.patiend_id not in 
    (select patient_id from TABLENAME p2
     where p2.related_id = p1.related_id)

【讨论】:

  • 所以我在想这样的事情,但它只是让我回到了我开始的地方。如果我有一个包含 2->1 和 1->2 的列表,则添加倒数会得到 2->1、1->2、1->2 和 2->1。与众不同的是,这只是让我们回到了起点。
  • 试试我上面修改后的答案。我现在不在数据库附近,所以没办法尝试。
猜你喜欢
  • 1970-01-01
  • 2018-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-14
  • 2015-07-24
相关资源
最近更新 更多