2012-10-21 14 views
6

Mam nadzieję, że tytuł jest wystarczająco jasny. Implementowałem logiczne AND/OR dla struktur drzewa, które są przechowywane w bazie danych, przy użyciu prostych węzłów i tabeli powiązań rodzic-dziecko. Drzewo próbka ma strukturę takiego:Alternatywy dla pełnego sprzężenia zewnętrznego dla logicznego OR w zapytaniu o strukturę drzewa

nodes and their children

Próbkę struktura drzewa zapytania jest następująca:

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

podwójne linie na wzór zapytania oznacza, że ​​A ma dziecko typu B (gdzieś w dół jego węzłów potomnych) LUB C. Zaimplementowałem A -> HASCHILD -> C -> HASCHILD -> E z łączeniem wewnętrznym, i A -> HASCHILD -> B -> HASCHILD -> Zaimplementowano E lubię to. Sztuczka polega na połączeniu tych dwóch gałęzi na A. Ponieważ jest to operacja OR, gałąź B lub gałąź C mogą nie istnieć. Jedyną metodą, jaką mogłem wymyślić, aby użyć pełnych zewnętrznych sprzężeń dwóch gałęzi z kluczem A's node_id. Aby uniknąć szczegółów, pozwól mi dać tego uproszczonego fragment z mojej kwerendy 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 

Ta kwerenda łączy dwa jako co faktycznie reprezentują tę samą using NODE_ID, a jeśli nie istnieje B lub C, przerwy nic. Zestaw wyników ma oczywiście duplikaty, ale mogę z tym żyć. Nie mogę jednak wymyślić innego sposobu wdrożenia OR w tym kontekście. AND są łatwe, są wewnętrznymi złączeniami, ale lewe sprzężenie zewnętrzne to jedyne podejście, które pozwala mi połączyć As. UNION ALL z fikcyjnymi kolumnami dla obu gałęzi nie jest opcją, ponieważ nie mogę się połączyć jak w tym przypadku.

Masz jakieś alternatywy dla tego, co tu robię?

UPDATE

sugestia TokenMacGuy daje mi drogę czystsze niż to, co mam w tej chwili. Powinienem był pamiętać o UNII. Korzystając z pierwszego zaproponowanego przeze mnie podejścia, mogę zastosować rozkład wzoru zapytania, który byłby spójnym sposobem na rozbijanie zapytań za pomocą operatorów logicznych. Poniżej znajduje się graficzne przedstawienie tego, co mam zamiar zrobić, tylko w przypadku, gdy ktoś inny pomaga wizualizować proces:

Tree query decomposition

To pomaga mi zrobić wiele fajnych rzeczy, w tym tworzenie piękny rezultat zestaw, w którym elementy wzoru zapytania są powiązane z wynikami. Rozmyślnie unikałem szczegółów tabel i innych kontekstów, ponieważ moje pytanie dotyczy sposobu dołączania wyników zapytań. Jak radzę sobie z hierarchią w DB to inny temat, którego chciałbym uniknąć. Dodam więcej szczegółów do komentarzy. Jest to w zasadzie tabela EAV połączona z tabelą hierarchii. Tylko w przypadku, gdy ktoś chciałby go zobaczyć, tutaj jest kwerenda biegnę bez uproszczeń, po wykonaniu sugestii TokenMacGuy za:

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

mógłbyś zawierać przykładowe dane , a niektóre przykłady wymaganych wyników? – MatBailie

+0

dlaczego theta dołącza do 'children @> array [node_id]'; czy equijoin 'child = node_id' nie byłby bardziej naturalny? w jaki sposób wyraziłeś ograniczenie klucza obcego między tymi tabelami? – SingleNegationElimination

+0

1) Pokaż nam definicję stołu 2) dlaczego przechowujesz dziecko; normalnie wystarczałoby przechowywanie rodziców B i C. 3) ograniczenie typu węzła powinno być w definicji klasy, a nie na poziomie instancji (choć będzie wymuszone na poziomie instancji!). – wildplasser

Odpowiedz

3

relacyjny równoważne ∨ jest ⋃.Można użyć union połączyć a JOIN b JOIN e z a JOIN c JOIN e lub po prostu użyć Związku B i C oraz dołączyć na powstałej w połączeniu związku, coś jak a JOIN (b UNION c) JOIN e

pełniej:

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;