2016-09-08 14 views
8

W jaki sposób chciałbym użyć wyniku rekurencyjnego CTE w zapytaniu, które planuję uruchomić z Ecto? Na przykład załóżmy, że mam tabeli, węzły, strukturę tak:Korzystanie z rekursywnego CTE z Ecto

-- nodes table example -- 

id parent_id 
1 NULL 
2 1 
3 1 
4 1 
5 2 
6 2 
7 3 
8 5 

i mam również inny nodes_users tabeli strukturę tak:

-- nodes_users table example -- 

node_id user_id 
1   1 
2   2 
3   3 
5   4 

Teraz chcę, aby pobrać wszystkie użytkownikom węzeł na poziomie lub powyżej określonego węzła, przez wzgląd na przykład niech wybrać węzeł w/id 8.

mogę użyć następującego zapytania rekurencyjnego zrobić tak:

WITH RECURSIVE nodes_tree AS (
    SELECT * 
    FROM nodes 
    WHERE nodes.id = 8 
UNION ALL 
    SELECT n.* 
    FROM nodes n 
    INNER JOIN nodes_tree nt ON nt.parent_id = n.id 
) 
SELECT u.* FROM users u 
INNER JOIN users_nodes un ON un.user_id = u.id 
INNER JOIN nodes_tree nt ON nt.id = un.node_id 

ten powinien powrócić użytkowników. * Dla użytkowników w/id 1, 2 i 4.

Nie jestem pewien, w jaki sposób mogę uruchomić tę samą kwerendę za pomocą ekto, najlepiej w sposób, który mógłby powrócić łańcuchowe wyjście. Rozumiem, że mogę wstawić surowe zapytanie SQL do mojej kwerendy za pomocą makra fragmentu, ale nie jestem do końca pewny, gdzie to by się za tym posłużyło, a nawet czy byłoby to najbardziej odpowiednią drogą do podjęcia.

Pomoc i/lub sugestie będą mile widziane!

Odpowiedz

11

Udało mi się to zrobić za pomocą fragmentu. Oto przykład kodu, którego użyłem. Prawdopodobnie przeniesię tę metodę do procedury przechowywanej.

Repo.all(MyProj.User, 
    from u in MyProj.User, 
    join: un in MyProj.UserNode, on: u.id == un.user_id, 
    join: nt in fragment(""" 
    (
    WITH RECURSIVE node_tree AS (
     SELECT * 
     FROM nodes 
     WHERE nodes.id = ? 
    UNION ALL 
     SELECT n.* 
     FROM nodes n 
     INNER JOIN node_tree nt ON nt.parent_id == n.id 
    ) 
) SELECT * FROM node_tree 
    """, ^node_id), on: un.node_id == nt.id 
)