web-dev-qa-db-ja.com

WITH RECURSIVEと再帰用語の和集合

PostgreSQLでWITH RECURSIVEクエリを使用することは可能ですか?ここで、再帰的な用語は異なるテーブルの結合です。私のユースケースは、テーブルといくつかの論理ルールからいくつかのタプルを抽出することです:

p_1(x_1,x_2,x_3,x_4,x_5,x_6,x_7) \wedge x_6\neq\texttt{NULL} \wedge x_2 \neq\texttt{NULL}\wedge x_5 \neq\texttt{NULL} \Rightarrow p_2(x_2,x_6)

そして、私は次の構文を持つ再帰クエリを活用したいと思います:

WITH RECURSIVE cte_name(
    CTE_query_definition -- non-recursive term
    UNION
    CTE_query definion  -- recursive term
) SELECT * FROM cte_name;

ここで、p1およびp3は、さまざまなタイプのタプルにすることができます。つまり、私の再帰的でない用語は次のようになります。

SELECT * from TUPLES

再帰的な用語はデータから新しいタプルを生成しますが、既存のタプルを生成する必要はありません(UNIONのあるCTEとALLのないCTE)。

SELECT 
       'ex' AS type_event,
       t1.arg2 AS arg1,
       t1.arg6 AS arg2,
       null AS arg3,
       null AS arg4,
       null AS arg5,
       null AS arg6
    FROM cte_name t1
    WHERE t1.type_event = 'Transfering'
      AND t1.arg2 = t2.arg1
      AND t1.arg6 = t2.arg2

UNION ALL 


       'ex' AS type_event,
       t1.arg2 AS arg1,
       t1.arg6 AS arg2,
       null AS arg3,
       null AS arg4,
       null AS arg5,
       null AS arg6
    FROM cte_name t1
    WHERE t1.type_event = 'Replacement'
      AND t1.arg2 = t2.arg1
      AND t1.arg6 = t2.arg2
UNION ALL

       'ex' AS type_event,
       t1.arg2 AS arg1,
       t1.arg1 AS arg2,
       null AS arg3,
       null AS arg4,
       null AS arg5,
       null AS arg6
    FROM cte_name t1
    WHERE t1.type_event = 'ex'

ちなみに、WITH RECURSIVEでは、再帰的な要素がさまざまな選択の和集合である再帰的なステートメントを表現できません。これをC++/Java/Pythonでプログラムで実装する必要がない効率的なソリューションはありますか?これにより、すべてのデータがデータベースに「とどまる」ため、データを複数回シリアル化および非シリアル化する必要がなくなりますか?

TUPLESの入力データの例:

+-------------+------+------+------+------+------+------+
| type_event  | arg1 | arg2 | arg3 | arg4 | arg5 | arg6 |
+-------------+------+------+------+------+------+------+
| ex          | A    | B    | null | null | null | null |
+-------------+------+------+------+------+------+------+
| Transfering | A    | B    | C    | D    | E    | F    |
+-------------+------+------+------+------+------+------+
| Replacement | G    | H    | I    | J    | K    | L    |
+-------------+------+------+------+------+------+------+

3番目と最後の反復後の予想される出力:

+-------------+------+------+------+------+------+------+
| type_event  | arg1 | arg2 | arg3 | arg4 | arg5 | arg6 |
+-------------+------+------+------+------+------+------+
| ex          | A    | B    | null | null | null | null |
+-------------+------+------+------+------+------+------+
| Transfering | A    | B    | C    | D    | E    | F    |
+-------------+------+------+------+------+------+------+
| Replacement | G    | H    | I    | J    | K    | L    |
+-------------+------+------+------+------+------+------+
| ex          | B    | F    | null | null | null | null |
+-------------+------+------+------+------+------+------+
| ex          | H    | L    | null | null | null | null |
+-------------+------+------+------+------+------+------+
| ex          | B    | A    | null | null | null | null |
+-------------+------+------+------+------+------+------+
| ex          | F    | B    | null | null | null | null |
+-------------+------+------+------+------+------+------+
| ex          | L    | H    | null | null | null | null |
+-------------+------+------+------+------+------+------+
2
jackb

目的の再帰的な用語の3つの部分は同じCTEから行を選択するため、それらを単一のSELECTに変換できます。

SELECT ...
FROM cte_name t1
WHERE (t1.type_event = 'Transfering' AND t1.arg2 = t2.arg1 AND t1.arg6 = t2.arg2)
   OR (t1.type_event = 'Replacement' AND t1.arg2 = t2.arg1 AND t1.arg6 = t2.arg2)
   OR (t1.type_event = 'ex')

列の並べ替えは CASE式 で実行できます。

SELECT 'ex' AS type_event,   -- same for all three
       t1.arg2 AS arg1,      -- same for all three
       CASE t1.type_event
         WHEN 'Transfering' THEN t1.arg6
         WHEN 'Replacement' THEN t1.arg6
         WHEN 'ex'          THEN t1.arg1
       END AS arg2,
       ...
1
CL.