MySQL 将多对多 table 转换为一对一
MySQL convert many-to-many table into one-to-one
我有一个 table,它是通过连接 2 个 table 创建的,现在这两列看起来有 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
我想将上面的 table 转换成下面的内容;
tbl1
id1
id2
1
10
2
20
或
tbl2
id1
id2
1
20
2
10
如何编写 SQL 查询以将 test
table 转换为 tbl1
或 tbl2
?
好的。要强制 table 具有唯一列,您只需在 table 上添加唯一索引即可。 (随时更改为索引中更好的名称)。
CREATE UNIQUE INDEX my_index_name_1 ON test(id1);
CREATE UNIQUE INDEX my_index_name_2 ON test(id2);
那么索引将不允许任何重复项。
(上面创建的索引不能有重复项。)
但是....如果您可以完全控制数据库,那么如果只有一对一的关系,那么使用这种 table 似乎有点奇怪。然后,您可以只在两个主要 table 上添加一个字段。
如果 id 来自 tables 'Table1' 和 'Table2' 您可以在 Table1 中有一个字段,称为 table2_id 并指向中的行table2。在 Table2 中,您可以有一个名为 table1_id 的字段,它会指向 table1。然后你可以跳过这个 table 并且所有搜索都会更快。但当然这可能是不可能的。无论如何只是想提一下...
起初我误解了这个问题,所以这是我的新答案。
据我了解,您想删除行,以便仅剩下的行是唯一的,删除哪些行并不重要?如果是这样,此解决方案将起作用:
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 的行之外的所有行。
请在运行之前对其进行测试并进行备份,我当然已经在我这边进行了测试,但仍然如此。
这将删除我的其他答案的评论中提到的唯一值。
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
如果我有什么误解,请告诉我。
关系数据库在设计上没有recommend/allow多对多关系。然而,对于这个特定的要求,下面的代码应该更接近你想要的。代码在 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;
我有一个 table,它是通过连接 2 个 table 创建的,现在这两列看起来有 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 |
我想将上面的 table 转换成下面的内容;
tbl1
id1 | id2 |
---|---|
1 | 10 |
2 | 20 |
或
tbl2
id1 | id2 |
---|---|
1 | 20 |
2 | 10 |
如何编写 SQL 查询以将 test
table 转换为 tbl1
或 tbl2
?
好的。要强制 table 具有唯一列,您只需在 table 上添加唯一索引即可。 (随时更改为索引中更好的名称)。
CREATE UNIQUE INDEX my_index_name_1 ON test(id1);
CREATE UNIQUE INDEX my_index_name_2 ON test(id2);
那么索引将不允许任何重复项。 (上面创建的索引不能有重复项。)
但是....如果您可以完全控制数据库,那么如果只有一对一的关系,那么使用这种 table 似乎有点奇怪。然后,您可以只在两个主要 table 上添加一个字段。
如果 id 来自 tables 'Table1' 和 'Table2' 您可以在 Table1 中有一个字段,称为 table2_id 并指向中的行table2。在 Table2 中,您可以有一个名为 table1_id 的字段,它会指向 table1。然后你可以跳过这个 table 并且所有搜索都会更快。但当然这可能是不可能的。无论如何只是想提一下...
起初我误解了这个问题,所以这是我的新答案。 据我了解,您想删除行,以便仅剩下的行是唯一的,删除哪些行并不重要?如果是这样,此解决方案将起作用:
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 的行之外的所有行。 请在运行之前对其进行测试并进行备份,我当然已经在我这边进行了测试,但仍然如此。
这将删除我的其他答案的评论中提到的唯一值。
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
如果我有什么误解,请告诉我。
关系数据库在设计上没有recommend/allow多对多关系。然而,对于这个特定的要求,下面的代码应该更接近你想要的。代码在 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;