2012-10-21 10 views
6

Spero che il titolo sia abbastanza chiaro. Ho implementato l'AND/OR logico per le strutture ad albero che sono conservate nel database, usando un semplice nodo e una tabella di associazione genitore-figlio. Un albero campione ha una struttura come questa:Alternative al join esterno completo per OR logico nella query struttura ad albero

nodes and their children

Un'interrogazione struttura ad albero di esempio è il seguente:

A contains children of certain types, which in turn contain other nodes

Le doppie linee nel motivo interrogazione significare che A ha un bambino di tipo B (da qualche parte verso il basso i suoi nodi figli) OPPURE C. Ho implementato A -> HASCHILD -> C -> HASCHILD -> E con un join interno, e A -> HASCHILD -> B -> HASCHILD -> E è implementato come questo. Il trucco è unire questi due rami su A. Poiché questa è un'operazione OR, il ramo B o il ramo C potrebbero non esistere. L'unico metodo che potrei pensare se utilizzare i join esterni completi di due rami con l'ID node_id come chiave. Per evitare i dettagli, lasciatemi fare questo frammento semplificato dalla mia query SQL:

WITH A as (....), 
    B as (....), 
    C as (....), 
    ...... 

SELECT * 
     from 
      A 
      INNER JOIN A_CONTAINS_B ON A.NODE_ID = A_CONTAINS_B.parent 
      INNER JOIN B ON A_CONTAINS_B.children @> ARRAY[B.NODE_ID] 
      INNER JOIN ..... 

      full OUTER JOIN -- THIS IS WHERE TWO As ARE JOINED 
      (select 
      A2.NODE_ID AS A2_NODE_ID 
      from 
      A2 
      INNER JOIN A_CONTAINS_C ON A2.NODE_ID = C_CONTAINS_C.parent 
      INNER JOIN C ON A_CONTAINS_C.children @> ARRAY[C.NODE_ID] 
      INNER JOIN ....) 
      as other_branch 
      ON other_branch.A2_NODE_ID = A.NODE_ID 

collega questa interrogazione due come che in realtà rappresentano la stessa A usando NODE_ID, e se B o C non esiste, tutto funzioni a dovere. Ovviamente il set di risultati ha dei duplicati, ma posso conviverci. Non riesco tuttavia a pensare ad un altro modo per implementare OR in questo contesto. Gli AND sono facili, sono join interni, ma left outer join è l'unico approccio che mi permette di connettere come. UNION ALL con le colonne dummy per entrambi i rami non è un'opzione perché non riesco a connettermi come in quel caso.

Avete qualche alternativa a quello che sto facendo qui?

UPDATE

suggerimento di TokenMacGuy mi dà un percorso più pulito di quello che ho in questo momento. Avrei dovuto ricordare UNION. Utilizzando il primo approccio che ha suggerito, posso applicare una scomposizione del modello di query, che sarebbe un modo coerente di abbattere le query con gli operatori logici. Quanto segue è una rappresentazione visiva di quello che ho intenzione di fare, nel caso in cui essa aiuta a qualcun altro a visualizzare il processo:

Tree query decomposition

Questo mi aiuta a fare un sacco di belle cose, tra cui la creazione di un bel risultato imposta dove i componenti del modello di query sono collegati ai risultati. Ho deliberatamente evitato i dettagli di tabelle o altri contesti, perché la mia domanda riguarda come unire i risultati delle query. Il modo in cui gestisco la gerarchia in DB è un argomento diverso che vorrei evitare. Aggiungerò ulteriori dettagli nei commenti. Si tratta fondamentalmente di una tabella EAV accompagnata da una tabella gerarchica. Nel caso in cui qualcuno vorrebbe vederlo, qui è la query sto correndo senza semplificazioni, dopo aver seguito il suggerimento di TokenMacGuy:

WITH 
    COMPOSITION1 as (select comp1.* from temp_eav_table_global as comp1 
         WHERE 
         comp1.actualrmtypename = 'COMPOSITION'), 
    composition_contains_observation as (select * from parent_child_arr_based), 
    OBSERVATION as (select obs.* from temp_eav_table_global as obs 
         WHERE 
         obs.actualrmtypename = 'OBSERVATION'), 
    observation_cnt_element as (select * from parent_child_arr_based), 
    OBS_ELM as (select obs_elm.* from temp_eav_table_global as obs_elm 
         WHERE 
         obs_elm.actualrmtypename= 'ELEMENT'), 

    COMPOSITION2 as (select comp_node_tbl2.* from temp_eav_table_global as comp_node_tbl2 
          where 
          comp_node_tbl2.actualrmtypename = 'COMPOSITION'), 
    composition_contains_evaluation as (select * from parent_child_arr_based), 
    EVALUATION as (select eva_node_tbl.* from temp_eav_table_global as eva_node_tbl 
          where 
          eva_node_tbl.actualrmtypename = 'EVALUATION'), 
    eval_contains_element as (select * from parent_child_arr_based), 
    ELEMENT as (select el_node_tbl.* from temp_eav_table_global as el_node_tbl 
          where 
          el_node_tbl.actualrmtypename = 'ELEMENT') 



select 
         'branch1' as branchid, 
         COMPOSITION1.featuremappingid as comprootid, 
         OBSERVATION.featuremappingid as obs_ftid, 
         OBSERVATION.actualrmtypename as obs_tn, 
         null as ev_ftid, 
         null as ev_tn, 
         OBS_ELM.featuremappingid as obs_elm_fid, 
         OBS_ELm.actualrmtypename as obs_elm_tn, 
         null as ev_el_ftid, 
         null as ev_el_tn 

         from 
         COMPOSITION1 
         INNER JOIN composition_contains_observation ON COMPOSITION1.featuremappingid = composition_contains_observation.parent 
         INNER JOIN OBSERVATION ON composition_contains_observation.children @> ARRAY[OBSERVATION.featuremappingid] 
         INNER JOIN observation_cnt_element on observation_cnt_element.parent = OBSERVATION.featuremappingid 
         INNER JOIN OBS_ELM ON observation_cnt_element.children @> ARRAY[obs_elm.featuremappingid] 

UNION 

SELECT     
         'branch2' as branchid, 
         COMPOSITION2.featuremappingid as comprootid, 
         null as obs_ftid, 
         null as obs_tn, 
         EVALUATION.featuremappingid as ev_ftid, 
         EVALUATION.actualrmtypename as ev_tn, 
         null as obs_elm_fid, 
         null as obs_elm_tn, 
         ELEMENT.featuremappingid as ev_el_ftid, 
         ELEMENT.actualrmtypename as ev_el_tn      
        from 
         COMPOSITION2 
         INNER JOIN composition_contains_evaluation ON COMPOSITION2.featuremappingid = composition_contains_evaluation.parent 
         INNER JOIN EVALUATION ON composition_contains_evaluation.children @> ARRAY[EVALUATION.featuremappingid] 
         INNER JOIN eval_contains_element ON EVALUATION.featuremappingid = eval_contains_element.parent 
         INNER JOIN ELEMENT on eval_contains_element.children @> ARRAY[ELEMENT.featuremappingid] 
+0

Potrebbe includere alcuni dati di esempio e alcuni esempi dei risultati richiesti? – MatBailie

+0

perché theta unisce 'children @> array [node_id]'; non sarebbe un equijoin 'child = node_id' essere più naturale? come hai espresso il vincolo di chiave esterna tra queste tabelle? – SingleNegationElimination

+0

1) Mostraci la/e tabella/i 2) perché conservi i figli di una persona; normalmente sarebbe sufficiente memorizzare il genitore di B e C. 3) il vincolo del tipo di nodo dovrebbe essere alla definizione della classe, non a livello di istanza (anche se verrà applicato a livello di istanza!) – wildplasser

risposta

3

l'equivalente relazionale per ∨ è ⋃.Si potrebbe usare sia union per combinare a JOIN b JOIN e con a JOIN c JOIN e o semplicemente usare l'unione di B e C e di unirsi a risultante, relazione combinato, qualcosa come a JOIN (b UNION c) JOIN e

più compiutamente:

SELECT * 
FROM a 
JOIN (
    SELECT 
     'B' source_relation, 
     parent, 
     b.child, 
     b_thing row_from_b, 
     NULL row_from_c 
    FROM a_contains_b JOIN b ON a_contains_b.child = b.node_id 

    UNION 
    SELECT 
     'C', 
     parent 
     c.child, 
     NULL, 
     c_thing 
    FROM a_contains_c JOIN c ON a_contains_c.child = c.node_id 
) a_c ON A.NODE_ID = a_e.parent 
JOIN e ON a_c.child = e.node_id; 
Problemi correlati