There are 2 input tables, objective is to assign value in Table 1 based on Previous ID & Next ID mapping present in Table 2
Edited Input Table 1:
ID | value |
---|---|
123 | null |
456 | null |
789 | maths |
246 | english |
135 | chemistry |
76899 | null |
Edited Input Table 2:
Previous ID | Next ID |
---|---|
246 | 123 |
135 | 456 |
123 | 123 |
456 | 456 |
Edited Output:
ID | Value |
---|---|
123 | english |
456 | chemitry |
789 | maths |
246 | english |
135 | chemistry |
76899 | null |
For example, for ID 123, it's previous ID 246 has a value of english in Table 2, hence the same should be assigned to ID 123 in value column of Table 1
Edit: It would good to have a select based solution instead of Update/Merge, thanks!
You can use an OUTER JOIN
:
SELECT t1.id,
COALESCE(p.value, t1.value) AS value
FROM table_1 t1
LEFT OUTER JOIN (
table_2 t2
INNER JOIN table_1 p
ON (t2.previous_id = p.id)
)
ON ( t1.id = t2.next_id
AND t2.previous_id != t2.next_id )
or:
SELECT t1.id,
COALESCE(p.value, t1.value) AS value
FROM table_2 t2
INNER JOIN table_1 p
ON (t2.previous_id = p.id)
RIGHT OUTER JOIN table_1 t1
ON ( t1.id = t2.next_id
AND t2.previous_id != t2.next_id )
or a correlated sub-query:
SELECT t1.id,
COALESCE(
( SELECT p.value
FROM table_2 t2
INNER JOIN table_1 p
ON (t2.previous_id = p.id)
WHERE t1.id = t2.next_id
AND t2.previous_id != t2.next_id
),
t1.value
) AS value
FROM table_1 t1
Or, if you can have multiple levels of previous_id
/next_id
pairs then you can use a hierarchical query:
SELECT t1.id,
COALESCE(
( SELECT p.value
FROM table_2 t2
INNER JOIN table_1 p
ON (t2.previous_id = p.id)
WHERE CONNECT_BY_ISLEAF = 1
START WITH
t1.id = t2.next_id
AND t2.previous_id != t2.next_id
CONNECT BY NOCYCLE
PRIOR t2.previous_id = t2.next_id
AND t2.previous_id != t2.next_id
),
t1.value
) AS value
FROM table_1 t1
Which, for the sample data:
CREATE TABLE table_1 (ID, value) AS
SELECT 123, null FROM DUAL UNION ALL
SELECT 456, null FROM DUAL UNION ALL
SELECT 76899, null FROM DUAL UNION ALL
SELECT 789, 'maths' FROM DUAL UNION ALL
SELECT 246, 'english' FROM DUAL UNION ALL
SELECT 1234, 'physics' FROM DUAL UNION ALL
SELECT 6789, 'biology' FROM DUAL UNION ALL
SELECT 135, 'chemistry' FROM DUAL;
CREATE TABLE Table_2 (Previous_ID, Next_ID) AS
SELECT 246, 123 FROM DUAL UNION ALL
SELECT 135, 456 FROM DUAL UNION ALL
SELECT 123, 123 FROM DUAL UNION ALL
SELECT 1234, 6789 FROM DUAL UNION ALL
SELECT 6789, 6789 FROM DUAL UNION ALL
SELECT 456, 456 FROM DUAL;
All output:
ID | VALUE |
---|---|
123 | english |
456 | chemistry |
76899 | null |
789 | maths |
246 | english |
1234 | physics |
6789 | physics |
135 | chemistry |
If you want to UPDATE
the table (rather than just SELECT
ing from the table) then you can use either of the correlated sub-queries from my 3rd or 4th suggestions and use that in the UPDATE
. For example:
UPDATE table_1 t1
SET value = COALESCE(
( SELECT p.value
FROM table_2 t2
INNER JOIN table_1 p
ON (t2.previous_id = p.id)
WHERE CONNECT_BY_ISLEAF = 1
START WITH
t1.id = t2.next_id
AND t2.previous_id != t2.next_id
CONNECT BY NOCYCLE
PRIOR t2.previous_id = t2.next_id
AND t2.previous_id != t2.next_id
),
t1.value
);
Would update the table even when there are multiple levels of indirection in table_2
.