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
