如何在MySQL连接(同一个表)中选择具有传递性的不同对?

时间:2013-07-13 17:11:55

标签: mysql sql

我正面临一个设计非常糟糕的数据库,其中包含非规范化的表格X. 该表X应与另一个表Y具有N:M关系。

问题在于,这种关系目前是1:N,而且直到现在这个简单的解决方案是在有各种注册管理机构相关时复制这些条目。

简化,我有这个:

| ID | TEXT | LOCATION_ID |
| 1  | foo  |      1      |
| 2  | foo  |      2      |
| 3  | bar  |      1      |
| 4  | bar  |      4      |
| 5  | bar  |      3      |

我必须将此表标准化。所以,我的第一个想法是尝试获得成对的类似注册表。像这样:

| a.ID | b.ID | 
|   1  |  2   |
|   3  |  4   |
|   3  |  5   |

尝试一下:

SELECT a.id, b.id 
FROM mytable AS a 
INNER JOIN mytable AS b 
   ON a.text = b.text AND a.id != b.id 
GROUP BY a.id, b.id

这导致了这样的问题:

| a.ID | b.ID | 
|   1  |  2   |
|   2  |  1   |
|   3  |  4   |
|   3  |  5   |
|   4  |  3   |
|   4  |  5   |
|   5  |  3   |
|   5  |  4   |

这些配对是重复的。

经过一番挖掘,我意识到这更有效:

SELECT a.id, b.id 
FROM mytable AS a 
INNER JOIN mytable AS b 
        ON a.text = b.text AND a.id < b.id 
GROUP BY a.id, b.id

所以,我得到了这个:

| a.ID | b.ID | 
|   1  |  2   |
|   3  |  4   |
|   3  |  5   |
|   4  |  5   |

但我仍然需要摆脱最后一个注册。

1 个答案:

答案 0 :(得分:8)

仅在一侧进行分组,并取另一方的MIN()

SELECT   MIN(a.ID) a, b.ID b
FROM     mytable a JOIN mytable b ON b.text = a.text AND b.ID > a.ID
GROUP BY b.ID

sqlfiddle上查看。