Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Criando uma tabela/exibição nivelada de um conjunto de dados definido hierarquicamente


Então o que você quer é materializar os fechamentos transitivos. Ou seja, dada essa tabela de aplicação...
 ID   | PARENT_ID
------+----------
    1 | 
    2 |         1
    3 |         2
    4 |         2
    5 |         4

... a tabela do gráfico ficaria assim:
 PARENT_ID | CHILD_ID
-----------+----------
         1 |        2
         1 |        3
         1 |        4
         1 |        5
         2 |        3
         2 |        4
         2 |        5
         4 |        5

É possível manter uma tabela como esta no Oracle, embora você precise rolar seu próprio framework para ela. A questão é se vale a pena a sobrecarga. Se a tabela de origem for volátil, manter os dados do gráfico atualizados pode custar mais ciclos do que você economizará nas consultas. Só você conhece o perfil dos seus dados.

Eu não acho que você possa manter uma tabela de gráficos com consultas CONNECT BY e chaves estrangeiras em cascata. Muita atividade indireta, muito difícil de acertar. Além disso, uma visão materializada está fora, porque não podemos escrever uma consulta SQL que zapeie o 1->5 registro quando excluímos o registro de origem para ID=4 .

Então, sugiro que você leia um artigo chamado Mantendo Fechamento Transitivo de Gráficos em SQL por Dong, Libkin, Su e Wong. Isso contém muita teoria e um pouco de SQL (Oracle), mas lhe dará a base para construir o PL/SQL que você precisa para manter uma tabela de gráficos.

"você pode expandir a parte sobre isso ser muito difícil de manter com CONNECT BY/FKs em cascata? Se eu controlar o acesso à tabela e todas as inserções/atualizações/exclusões ocorrerem procedimentos armazenados em vias, que tipos de cenários existem em que isso quebraria?"

Considere o registro 1->5 que é um curto-circuito de 1->2->4->5 . Agora, o que acontece se, como eu disse antes, excluirmos o registro de origem de ID=4 ? Chaves estrangeiras em cascata podem excluir as entradas para 2->4 e 4->5 . Mas isso deixa 1->5 (e de fato 2->5 ) na tabela do gráfico, embora não representem mais uma aresta válida no gráfico .

O que pode funcionar (acho que não fiz isso) seria usar uma chave sintética adicional na tabela de origem, assim.
 ID   | PARENT_ID | NEW_KEY
------+-----------+---------
    1 |           | AAA
    2 |         1 | BBB
    3 |         2 | CCC
    4 |         2 | DDD
    5 |         4 | EEE

Agora a tabela do gráfico ficaria assim:
 PARENT_ID | CHILD_ID | NEW_KEY
-----------+----------+---------
         1 |        2 | BBB
         1 |        3 | CCC
         1 |        4 | DDD
         1 |        5 | DDD
         2 |        3 | CCC
         2 |        4 | DDD
         2 |        5 | DDD
         4 |        5 | DDD

Portanto, a tabela de gráficos tem uma chave estrangeira que faz referência ao relacionamento na tabela de origem que a gerou, em vez de vincular ao ID. Em seguida, excluindo o registro para ID=4 iria em cascata exclusões de todos os registros na tabela de gráfico onde NEW_KEY=DDD .

Isso funcionaria se um determinado ID pudesse ter apenas zero ou um ID pai. Mas não funcionará se for permitido que isso aconteça:
 ID   | PARENT_ID
------+----------
    5 |         2
    5 |         4

Em outras palavras, a borda 1->5 representa tanto 1->2->4->5 e 1->2->5 . Portanto, o que pode funcionar depende da complexidade dos seus dados.