PostgreSQLのドキュメントでは、このトピックについて説明しています。そのページの再帰的 CTE の例を参照してください。
再帰的 CTE は把握するのが少し難しい場合がありますが、一度使用すると非常に強力です。ドキュメントを読んで、少し試してみてください。あなたはそれを得るでしょう。
(質問には常に PostgreSQL のバージョンを記載し、必要な出力を表形式で表示してください)。
与えられたデモ データ:
create table users (
userid integer primary key,
reporttouserid integer references users(userid)
);
insert into users(userid, reporttouserid) values (101,null), (102,101), (103,102);
(可能な場合は質問でこれを提供してください。作成するのは面倒です)
次のような方法でグラフを再帰的にたどることができます。
WITH RECURSIVE flatusers(userid, reporttouserid, baseuserid) AS (
SELECT userid, reporttouserid, userid AS baseuserid
FROM users WHERE reporttouserid IS NULL
UNION ALL
SELECT u.userid, u.reporttouserid, f.baseuserid
FROM flatusers f
INNER JOIN users u ON f.userid = u.reporttouserid
)
SELECT * FROM flatusers;
次のような出力を生成します。
userid | reporttouserid | baseuserid
--------+----------------+------------
101 | | 101
102 | 101 | 101
103 | 102 | 101
(3 rows)
そこからどこに行くべきかを理解できると確信しています。使用する前に、その再帰 CTEを理解していることを確認してください。
PostgreSQL (少なくとも 9.4 以前) は (残念ながら) 非再帰的な CTE であっても、quals を CTE 用語にプッシュダウンできないことに注意してください。クエリに追加WHERE baseuserid = 101
すると、クエリはフラット化されたテーブル全体を生成し、そのほとんどを破棄します。1 つのbaseuseridに対してのみこの再帰操作を実行する場合は、再帰 CTE 用語の静的結合部分のWHERE
後に適切な節用語を追加する必要があります。WHERE reporttouserid IS NULL