0

純粋にルビで再帰呼び出しを最適化するために苦労しています。私はpostgresqlデータベースにデータを移動しました。私はWITH RECURSIVE関数を利用してpostgresqlが提供したいと考えています。複数テーブルの再帰的なSQL文

すべての例では、メニューやカテゴリテーブルなどの単一のテーブルを使用しているようです。

私の状況は多少異なります。私は質問と答えのテーブルを持っています。

+----------------------+  +------------------+ 
| questions   |  | answers   | 
+----------------------+  +------------------+ 
| id     |  | source_id  | <- from question ID 
| start_node (boolean) |  | target_id  | <- to question ID 
| end_node (boolean) |  +------------------+ 
+----------------------+ 

私は、関連する回答によって一緒に接続されているすべての質問を取得したいと思います。

また、ツリー内の任意のノードからツリーのルートノードなど、別の方法でツリーに移動したいと考えています。 - 任意の

Q1 
|-- A1 
| '-- Q2 
|   |-- A2 
|   | '-- Q3 
|   '-- A3 
|    '-- Q4 
'-- A4 
     '-- Q5 

あなたが見ることができるように、質問が複数の発信疑問を持つことができますが、彼らはまた、複数の着信答えを持っていることができますグラフィカルな方法で質問・回答ツリーの別の例を与えることを

〜多人数。

誰かが良いアイデアを持っていることを願ったり、いくつかの例、記事、ガイドを教えてくれることを願っています。

皆さん、ありがとうございます。

よろしく、 エミール

+0

これは再帰的ではありません。質問は、質問に対する答えですか? (メタ質問、これは...) – wildplasser

+0

答えは質問に対する回答ですが、答えは別の質問などにつながります。だから鎖は無限に長くなる可能性があります。回答はチェーンの早期に渡された質問に戻る可能性があります。私はこれが質問に答えることを望みますか? –

答えて

1

これは、はるかに理想から遠いですが、参加する上で、私はそのように、再帰クエリの周りにプレーします:与え

WITH RECURSIVE questions_with_answers AS (
    SELECT 
     q.*, a.* 
    FROM 
     questions q 
    LEFT OUTER JOIN 
     answers a ON (q.id = a.source_id) 

    UNION ALL 

    SELECT 
     q.*, a.* 
    FROM 
     questions_with_answers qa 
    JOIN 
     questions q ON (qa.target_id = q.id) 
    LEFT OUTER JOIN 
     answers a ON (q.id = a.source_id) 
) 
SELECT * FROM questions_with_answers WHERE source_id IS NOT NULL AND target_id IS NOT NULL; 

は私は結果:

id | name | start_node | end_node | source_id | target_id 
----+------+------------+----------+-----------+----------- 
    1 | Q1 |   |   |   1 |   2 
    2 | A1 |   |   |   2 |   3 
    3 | Q2 |   |   |   3 |   4 
    3 | Q2 |   |   |   3 |   6 
    4 | A2 |   |   |   4 |   5 
    6 | A3 |   |   |   6 |   7 
    1 | Q1 |   |   |   1 |   8 
    8 | A4 |   |   |   8 |   9 
    2 | A1 |   |   |   2 |   3 
    3 | Q2 |   |   |   3 |   6 
    3 | Q2 |   |   |   3 |   4 
    4 | A2 |   |   |   4 |   5 
    6 | A3 |   |   |   6 |   7 
    8 | A4 |   |   |   8 |   9 
    3 | Q2 |   |   |   3 |   6 
    3 | Q2 |   |   |   3 |   4 
    6 | A3 |   |   |   6 |   7 
    4 | A2 |   |   |   4 |   5 
    6 | A3 |   |   |   6 |   7 
    4 | A2 |   |   |   4 |   5 
(20 rows) 
+0

こんにちは。このお返事ありがとうございます(!)。それは本当に素晴らしいです! 私はちょっと微調整しようとしましたが、チェーンの最後の質問を結果の表に含めることはできません。 私はここで要点を作成しました:https://gist.github.com/ekampp/cb871918adc0fc931cb02afa20c30651 –

+0

@EmilKampp、source_idとtarget_idに 'NOT NULL'条件があるためフィルタリングされていると思います。それを 'WHERE source_id IS NOT NULLまたはtarget_id IS NOT NULL;に変更しようとしてください。 ' – icuken

+0

はい、それも私が到着したものです。あなたの助けを借りてありがとう! :D –

1

実際には2つのテーブルは必要ありません。 この例を分析することをお勧めします。 2つではなく1つのテーブルを維持することは、特に再帰的なクエリに関しては、多くの問題を軽減します。

create table the_table (id int primary key, parent_id int); 
insert into the_table values 
(1, 0), -- root question 
(2, 1), 
(3, 1), 
(4, 2), 
(5, 2), 
(6, 1), 
(7, 3), 
(8, 0), -- root question 
(9, 8); 

ノードが問題であるかの答えは、ツリー内での位置に依存しているかどうか:

この最小限の構成は、必要なすべての情報が含まれています。もちろん、ノードのタイプに関する情報を含む列をテーブルに追加することができます。ご要望(コメント解除十分なwhere条件)の両方のための答えを得るために

使用このクエリ:

with recursive cte(id, parent_id, depth, type, root) as (
    select id, parent_id, 1, 'Q', id 
    from the_table 
    where parent_id = 0 
    -- and id = 1 <-- looking for list of a&q for root question #1 
union all 
    select 
     t.id, t.parent_id, depth+ 1, 
     case when (depth & 1)::boolean then 'A' else 'Q' end, c.root 
    from cte c 
    join the_table t on t.parent_id = c.id 
) 
select * 
from cte 
-- where id = 9 <-- looking for root question for answer #9 
order by id; 

id | parent_id | depth | type | root 
----+-----------+-------+------+------ 
    1 |   0 |  1 | Q | 1 
    2 |   1 |  2 | A | 1 
    3 |   1 |  2 | A | 1 
    4 |   2 |  3 | Q | 1 
    5 |   2 |  3 | Q | 1 
    6 |   1 |  2 | A | 1 
    7 |   3 |  3 | Q | 1 
    8 |   0 |  1 | Q | 8 
    9 |   8 |  2 | A | 8 
(9 rows) 

関係の子 - 親があいまいでないと、両側に適用されます。この情報を2回保存する必要はありません。言い換えれば、私たちが両親に関する情報を保管すると、子どもに関する情報は冗長です(逆もまた同様です)。 treeと呼ばれるデータ構造の基本的な特性の1つです。例を参照してください。

-- find parent of node #6 
select parent_id 
from the_table 
where id = 6; 

-- find children of node #6 
select id 
from the_table 
where parent_id = 6; 
+0

回答には、そうでなければ失われる質問との間の接続に関する情報が含まれているので、2つのテーブルが必要だと思いますか? –

+0

編集された回答を参照してください。 – klin