繁体   English   中英

MySQL 将多对多表转换为一对一

[英]MySQL convert many-to-many table into one-to-one

我有一个通过连接 2 个表创建的表,现在这两列看起来像具有many-to-many关系。 我想将其转换为one-to-one关系含义,两列中的值都必须是unique 这是一个示例设置;

create table Test(id1 integer, id2 integer);
insert into Test(id1, id2) values(1, 10);
insert into Test(id1, id2) values(1, 20);
insert into Test(id1, id2) values(2, 10);
insert into Test(id1, id2) values(2, 20);
select * from Test;
id1 id2
1 10
1 20
2 10
2 20

我想将上表转换为如下内容;

tbl1

id1 id2
1 10
2 20

或者

tbl2

id1 id2
1 20
2 10

如何编写 SQL 查询将test表转换为tbl1tbl2

这将取出我在其他答案的评论中提到的独特价值。

SELECT a.id1, b.id2
FROM (
    SELECT *, ROW_NUMBER() OVER (ORDER BY id1) AS RowNum FROM (SELECT DISTINCT id1 FROM test) x
) AS a,
(
    SELECT *, ROW_NUMBER() OVER (ORDER BY id2) AS RowNum FROM (SELECT DISTINCT id2 FROM test) x
) AS b
WHERE a.RowNum = b.RowNum

如果有什么我误解了,请告诉我。

好的。 要强制表具有唯一列,您只需在表上添加唯一索引。 (随时更改为索引上更好的名称)。

CREATE UNIQUE INDEX my_index_name_1 ON test(id1);
CREATE UNIQUE INDEX my_index_name_2 ON test(id2);

然后索引将不允许任何重复。 (创建上面的索引时不能有任何重复。)

但是....如果您可以完全控制数据库,那么如果只有 1 对 1 的关系,拥有这种类型的表似乎有点奇怪。 然后你可以在两个主表上添加一个字段。

如果 id 来自表 'Table1' 和 'Table2' 你可以在 Table1 中有一个名为 table2_id 的字段并指向 table2 中的行。 在 Table2 中,您可以有一个名为 table1_id 的字段,它将指向 table1。 然后你可以跳过这个表,所有的搜索都会更快。 但当然,这可能是有原因的。 反正就是想提一下...

我一开始误解了这个问题,所以这是我的新答案。 据我了解,您想删除行,所以剩下的唯一行是唯一的,删除哪些行并不重要? 如果是这样,此解决方案将起作用:

DELETE test
FROM test
JOIN (
    SELECT * FROM (
        SELECT t.id1, t.id2, (SELECT MAX(id2) FROM test WHERE id1 = t.id1) AS maxId2
            from test t
        ) AS r
    WHERE r.id2 != maxId2
) d
 ON d.id1 = test.id1 AND d.id2 = test.id2;

此查询将删除除具有最高 id2 的行之外的所有行。 请在运行之前对其进行测试并进行备份,我当然已经在我身边测试过它,但仍然如此。

关系数据库在设计上不推荐/允许多对多关系。 但是,对于这个特定的要求,下面的代码应该更接近你想要的。 代码在dbfiddle

create table tb11(id1 integer, id2 integer);
create table tb12(id1 integer, id2 integer);

INSERT INTO tb11  
SELECT id1, id2 FROM  
(SELECT
    id1,
    id2,
    RANK() OVER (PARTITION BY id2 ORDER BY id1 ASC) as rnk
FROM
    Test) t1 where t1.rnk = 1;

INSERT INTO tb12  
SELECT id1, id2 FROM  
(SELECT
    id1,
    id2,
    RANK() OVER (PARTITION BY id2 ORDER BY id1 ASC) as rnk
FROM
    Test) t2  where t2.rnk = 2;

SELECT * FROM tb11;
SELECT * FROM tb12;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM