Home > Net >  update sql to update lowest hierarchical data for each row in a table
update sql to update lowest hierarchical data for each row in a table

Time:05-11

I have a table as shown below

id previous_id latest_id
1 null null
2 1 null
3 2 null
4 null null
5 4 null
6 6 null

I want to update the table by setting the latest_id column value to lowest hierarchical value, which will look like this:

id previous_id latest_id
1 null 3
2 1 3
3 2 3
4 null 6
5 4 6
6 5 6

I have tried to use connect by, but the query is getting too complicated as start with cannot have a static value assigned, this update is for the entire table.

Below is what I could write for a single record based on it's id, how can I generalize it for all records in the table?

UPDATE TABLENAME1 
   SET LATEST_ID = (SELECT MAX(ID)
                      FROM TABLENAME1
                     START WITH ID = 3
                   CONNECT BY PREVIOUS_ID = PRIOR ID );

CodePudding user response:

You can use a correlated hierarchical query and filter to get the leaf rows:

UPDATE table_name t
SET latest_id = (SELECT id
                 FROM   table_name h
                 WHERE  CONNECT_BY_ISLEAF = 1
                 START WITH h.id = t.id
                 CONNECT BY previous_id = PRIOR id);

Which, for the sample data:

CREATE TABLE table_name (id, previous_id, latest_id) AS
SELECT 1, null, CAST(null AS NUMBER) FROM DUAL UNION ALL
SELECT 2, 1,    null FROM DUAL UNION ALL
SELECT 3, 2,    null FROM DUAL UNION ALL
SELECT 4, null, null FROM DUAL UNION ALL
SELECT 5, 4,    null FROM DUAL UNION ALL
SELECT 6, 5,    null FROM DUAL;

Updates the table to:

ID PREVIOUS_ID LATEST_ID
1 null 3
2 1 3
3 2 3
4 null 6
5 4 6
6 5 6

db<>fiddle here

CodePudding user response:

To the accepted answer, I will add this alterative which might perform better for large datasets by eliminating the correlated subquery.

MERGE INTO table_name t
USING (  
  SELECT      CONNECT_BY_ROOT(id) root_id, id latest_id
  FROM        table_name
  WHERE       connect_by_isleaf = 1
  CONNECT BY  previous_id = prior id ) u
ON ( t.id = u.root_id )
WHEN MATCHED THEN UPDATE SET t.latest_id = u.latest_id;
  • Related