简体   繁体   English

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

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

I have a table which is created by joining 2 tables and now the two columns looks like having a many-to-many relationship.我有一个通过连接 2 个表创建的表,现在这两列看起来像具有many-to-many关系。 I want to convert this to a one-to-one relationship meaning, values in both the columns has to be unique .我想将其转换为one-to-one关系含义,两列中的值都必须是unique Here is a sample setting;这是一个示例设置;

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 id1 id2 id2
1 1 10 10
1 1 20 20
2 2 10 10
2 2 20 20

I want to convert the above table into something as below;我想将上表转换为如下内容;

tbl1

id1 id1 id2 id2
1 1 10 10
2 2 20 20

OR或者

tbl2

id1 id1 id2 id2
1 1 20 20
2 2 10 10

How to write a SQL query to convert test table to tbl1 or tbl2 ?如何编写 SQL 查询将test表转换为tbl1tbl2

This will take out unique values as mentioned in the comments on my other answer.这将取出我在其他答案的评论中提到的独特价值。

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

Let me know if there is something I misunderstood.如果有什么我误解了,请告诉我。

Ok.好的。 To force the table to have unique columns you can just add a unique index on the table.要强制表具有唯一列,您只需在表上添加唯一索引。 (Feel free to change to better name on the index). (随时更改为索引上更好的名称)。

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

Then the indexes will not allow any duplicates.然后索引将不允许任何重复。 (There can't be any duplicates when you create the indexes above.) (创建上面的索引时不能有任何重复。)

But....if you have full control over the database it seems a bit strange to have this type of table if there are only 1 to 1 relations.但是....如果您可以完全控制数据库,那么如果只有 1 对 1 的关系,拥有这种类型的表似乎有点奇怪。 Then you could just add a fields on the two main tables instead.然后你可以在两个主表上添加一个字段。

If the ids are coming from the tables 'Table1' and 'Table2' you can have a field in Table1 which are called table2_id and pointing to the row in table2.如果 id 来自表 'Table1' 和 'Table2' 你可以在 Table1 中有一个名为 table2_id 的字段并指向 table2 中的行。 And in the Table2 you could have a field called table1_id and that would point to table1.在 Table2 中,您可以有一个名为 table1_id 的字段,它将指向 table1。 Then you could just skip this table and all searches would be faster.然后你可以跳过这个表,所有的搜索都会更快。 But of course there might be a reason this is not possible.但当然,这可能是有原因的。 Just wanted to mention it anyways...反正就是想提一下...

I misunderstood the question at first, so this is my new answer.我一开始误解了这个问题,所以这是我的新答案。 As I understand it you want to remove rows so the only rows left are unique and it does not matter which rows are deleted?据我了解,您想删除行,所以剩下的唯一行是唯一的,删除哪些行并不重要? If so, this solution will work:如果是这样,此解决方案将起作用:

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;

This query will delete all rows except the ones with the highest id2.此查询将删除除具有最高 id2 的行之外的所有行。 Please test it and make a backup before running it, I have of course tested it on my side but still.请在运行之前对其进行测试并进行备份,我当然已经在我身边测试过它,但仍然如此。

Relational databases do not recommend/allow many to many relationships by design.关系数据库在设计上不推荐/允许多对多关系。 However, for this specific requirement, following code should get closer to what you want.但是,对于这个特定的要求,下面的代码应该更接近你想要的。 Code is on a dbfiddle代码在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