Reputation: 894
I have a table which is created by joining 2 tables and now the two columns looks like having a many-to-many
relationship. I want to convert this to a one-to-one
relationship meaning, values in both the columns has to be 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 | id2 |
---|---|
1 | 10 |
1 | 20 |
2 | 10 |
2 | 20 |
I want to convert the above table into something as below;
tbl1
id1 | id2 |
---|---|
1 | 10 |
2 | 20 |
OR
tbl2
id1 | id2 |
---|---|
1 | 20 |
2 | 10 |
How to write a SQL query to convert test
table to tbl1
or tbl2
?
Upvotes: 2
Views: 377
Reputation: 61
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
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;
Upvotes: 0
Reputation: 1946
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.
Upvotes: 1
Reputation: 1946
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. Please test it and make a backup before running it, I have of course tested it on my side but still.
Upvotes: 0
Reputation: 1946
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. 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. And in the Table2 you could have a field called table1_id and that would point to 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...
Upvotes: 0