使用递归查询从 table 中获取电子邮件线程

Fetch email thread from a table with recursive query

我有一个 table emails:


     id     message_id          in_reply_to
      1     <me123@gmail.com>   null
      2     <me345@gmail.com>   <me123@gmail.com>
      3     <me567@gmail.com>   <me345@gmail.com>
      4     <me768@gmail.com>   <me567@gmail.com>
      5     <me910@gmail.com>   null
      6     <me911@gmail.com>   <me768@gmail.com>
      7     <me912@gmail.com>   <me567@gmail.com>
      8     <me913@gmail.com>   <me912@gmail.com>
      9     <me914@gmail.com>   <me913@gmail.com>
      10    <me915@gmail.com>   <me914@gmail.com>
      11    <me916@gmail.com>   <me914@gmail.com>
     ...

(这个table保存着邮件线程,我们需要获取邮件线程)

  1. 我只知道邮件的message_ididin_reply_to可以为空也可以不为空。
  2. 我需要获取那些消息的所有 message_ids 和 ids,其中 in_reply_to 等于我们知道的 message_id 并继续使用 in_reply_to。
  3. 获取 message_id 后,我需要搜索其他具有 in_reply_to 字段的电子邮件 message_id 并获取直到即将到来的 message_id 不是 in_reply_to 任何其他消息。
  4. in_reply_to 没有 foreign_key 关系 它只是一个列表,就像任何其他列一样。
  5. id 是电子邮件 table 的主键,message_id 对于每封电子邮件始终是唯一的。
  6. 一条 message_id 可以是 in_reply_to 条消息。

如果我通过 message_id = <me912@gmail.com>

我的输出table应该是

      id     message_id          in_reply_to      
      8     <me913@gmail.com>   <me912@gmail.com>
      9     <me914@gmail.com>   <me913@gmail.com>
      10    <me915@gmail.com>   <me914@gmail.com>
      11    <me916@gmail.com>   <me914@gmail.com>

我只知道我需要使用递归,但我无法理解 WITH RECURSIVE - https://www.postgresql.org/docs/current/queries-with.html

我试过这个:

    WITH RECURSIVE emails AS (
    SELECT message_id, in_reply_to FROM emails WHERE id = ?
    UNION ALL
    SELECT message_id, in_reply_to
     FROM emails where in_reply_to =  // Stuck here
   )
   SELECT * 
   FROM emails;

你能帮我解决这个问题吗?

加入 CTE 比较 email_idin_reply_to

WITH RECURSIVE
thread
AS
(
SELECT e.id,
       e.message_id,
       e.in_reply_to
       FROM emails e
       WHERE id = 8
UNION ALL
SELECT e.id,
       e.message_id,
       e.in_reply_to
       FROM emails e
            INNER JOIN thread t
                       ON t.message_id = e.in_reply_to
)
SELECT *
       FROM thread
       ORDER BY id;

db<>fiddle