Skip to Main Content

SQL & PL/SQL

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Hierarchical order of tables for data insertion

muttleychessOct 4 2024

I have a table called TB_TABELAS, which contains a list of table names used in a particular local application. I need to read this table and sort the tables in a way that they do not depend on the insertion of another table that is also in TB_TABELAS, or, if they do depend, that it has already been processed earlier.
Example: Suppose TB_TABELAS contains the table TABELA_A.
I need to look in the constraints to see if any of the FKs in TABELA_A reference any table contained in TB_TABELAS. The tables that do not have these references will be processed first, and for that, there is another table (TABELAS_ORDEM) where I must record this data. Once this is done, I need to determine the other hierarchical orders to read from TB_TABELAS and record the order in TABELAS_ORDEM, according to their dependencies.
I tried to implement and search the internet for some examples, but I am facing difficulties with the actual system tables available, as there are some constraints that seem a bit strange. I will try to post something similar to what's happening with the tables. Please ignore some of the constraints, as I am trying to simulate a real scenario I am facing.

CREATE TABLE TB_TABELAS ( NOME_TABELA VARCHAR2(30) PRIMARY KEY );


CREATE TABLE TABELAS_ORDEM (
    NOME_TABELA VARCHAR2(30),
    ORDEM NUMBER,
    DEPENDENCIAS VARCHAR2(4000)
);


INSERT  INTO TB_TABELAS (NOME_TABELA) VALUES ('CUSTOMERS');
INSERT  INTO TB_TABELAS (NOME_TABELA) VALUES ('PRODUCTS');
INSERT  INTO TB_TABELAS (NOME_TABELA) VALUES ('ORDERS');
INSERT  INTO TB_TABELAS (NOME_TABELA) VALUES ('ORDER_ITEMS');
INSERT  INTO TB_TABELAS (NOME_TABELA) VALUES ('CATEGORIES');
INSERT  INTO TB_TABELAS (NOME_TABELA) VALUES ('SUPPLIERS');
INSERT  INTO TB_TABELAS (NOME_TABELA) VALUES ('PAYMENT_METHODS');
INSERT  INTO TB_TABELAS (NOME_TABELA) VALUES ('COUNTRIES');




CREATE TABLE CATEGORIES (
  category_id NUMBER PRIMARY KEY,
  name VARCHAR2(100),
  description VARCHAR2(255)
);

CREATE TABLE COUNTRIES (
  country_id NUMBER PRIMARY KEY,
  country_name VARCHAR2(100),
  country_code VARCHAR2(5)
);


CREATE TABLE CUSTOMERS (
  customer_id NUMBER PRIMARY KEY,
  name VARCHAR2(100),
  email VARCHAR2(100),
  phone VARCHAR2(20),
  address VARCHAR2(200)
);

CREATE TABLE PRODUCTS (
  product_id NUMBER PRIMARY KEY,
  name VARCHAR2(100),
  price NUMBER,
  stock NUMBER,
  category_id  NUMBER,
  country_id NUMBER,
  FOREIGN KEY (category_id ) REFERENCES CATEGORIES (category_id ),
  FOREIGN KEY (country_id  ) REFERENCES COUNTRIES (country_id )
);

);

CREATE TABLE ORDERS (
  order_id NUMBER PRIMARY KEY,
  customer_id NUMBER,
  order_date DATE,
  total NUMBER,
  FOREIGN KEY (customer_id) REFERENCES CUSTOMERS(customer_id)
);

CREATE TABLE ORDER_ITEMS (
  order_item_id NUMBER PRIMARY KEY,
  order_id NUMBER,
  product_id NUMBER,
  quantity NUMBER,
  price NUMBER,
  CATEGORY_ID    NUMBER,
  FOREIGN KEY (order_id) REFERENCES ORDERS(order_id),
  FOREIGN KEY (product_id) REFERENCES PRODUCTS(product_id),
  FOREIGN KEY (category_id ) REFERENCES CATEGORIES (category_id )
  
);



CREATE TABLE SUPPLIERS (
  supplier_id NUMBER PRIMARY KEY,
  name VARCHAR2(100),
  contact_name VARCHAR2(100),
  phone VARCHAR2(20),
  address VARCHAR2(200)
);

CREATE TABLE PAYMENT_METHODS (
  payment_method_id NUMBER PRIMARY KEY,
  method_name VARCHAR2(50),
  details VARCHAR2(255)
);

When trying to execute the query below:

WITH pur AS (
    SELECT 
        table_name,
        constraint_type,
        constraint_name,
        r_constraint_name,
        MAX(DECODE(constraint_type, 'R', 1, 0)) OVER (PARTITION BY table_name) AS is_r
    FROM 
        user_constraints
    WHERE 
        constraint_type IN ('P', 'U', 'R')
), 
son_dad AS (
    SELECT DISTINCT 
        s.table_name AS son,
        d.table_name AS dad,
        d.constraint_type
    FROM 
        (SELECT * FROM pur WHERE constraint_type = 'R' OR is_r = 0) s
    LEFT JOIN pur d
        ON s.r_constraint_name = d.constraint_name
        AND s.table_name != d.table_name
),
hierarchical_relations AS (
    SELECT 
        LEVEL AS lvl,
        son,
        dad,
        constraint_type
    FROM 
        son_dad
    WHERE 
        son IN (SELECT nome_tabela FROM tb_tabelas)
        AND (dad IS NULL OR dad IN (SELECT nome_tabela FROM tb_tabelas))
    START WITH 
        dad IS NULL
    CONNECT BY NOCYCLE 
        PRIOR son = dad
    ORDER SIBLINGS BY 
        dad, son
)
SELECT 
    tb.nome_tabela AS son
    ,hr.dad,
    MIN(hr.lvl) AS lvl,  
    hr.constraint_type
FROM 
    tb_tabelas tb
LEFT JOIN 
    hierarchical_relations hr
    ON tb.nome_tabela = hr.son
GROUP BY 
    tb.nome_tabela, hr.dad, hr.constraint_type
ORDER BY 
   lvl nulls first, hr.dad NULLS FIRST,  tb.nome_tabela;

notice that ORDER_ITEMS appears before PRODUCTS, which means if I tried to insert into the ORDER_ITEMS table, it would throw an error, as I don't have PRODUCTS yet. In this case, I forced a constraint [FOREIGN KEY (category_id) REFERENCES CATEGORIES (category_id)] to make it resemble a real scenario that happens here.
Anyway, I can't express myself the way I want to, but I would like to arrange the tables contained in the TB_TABELAS table in an order that allows data insertion without dependency errors.

using:Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production

This post has been answered by Cookiemonster76 on Oct 4 2024
Jump to Answer
Comments
Post Details
Added on Oct 4 2024
6 comments
355 views