Oracle 中的递归查询

Recursive query in Oracle

我对 PLSQL 的更高级主题有点陌生,所以希望有人能帮助我。

问题: 我有一个 table,其中包含管理员和用户之间发送的消息。 table 有一个 message_parent 与 FK 到相同的 table message_id 字段:如果该字段被填充,则意味着该消息是作为对先前消息的回复发送的信息。我需要 select 属于同一对话的所有消息并显示它们。这可以通过单个查询来完成,还是我需要一个过程来处理这种逻辑?据我了解,它需要递归,因为我正在搜索的 message_id 总是在变化

例子 消息 table:

|message_id|parent_id|message_content|
|----------|---------|---------------|
|101       |100      | foo           |
|100       |97       | bar           |
|99        |(null)   | Left out      |
|97        |(null)   | baz           |

因此 selecting message_content 的正确查询应该 return "baz"、"bar" 和 "foo" 而不是 "Left out" (因为 baz 是原始消息)。 如果有例如,这将很简单只有两条消息可以捆绑在一起,或者例如thread_id 列,这将 link 所有消息都在同一个 'thread' 中,但是随着 parent_id 的不断变化,我很难弄明白。

在 Oracle 中,使用 CONNECT BY

可以轻松完成此操作
select message_id, parent_id, message_content
from messages
start with message_id = 97 -- this is the root of your conversation
connect by prior message_id = parent_id;

这会从上到下遍历树。

如果您想从一条消息到根遍历树,请更改 start withconnect by 部分:

select message_id, parent_id, message_content
from messages
start with message_id = 100 -- this is the root of your conversation
connect by prior parent_id = message_id; -- this now goes "up" in the tree

要根据单个 message_id 获取整个消息上下文,您可以使用两个分层查询。一个将消息树从当前消息 down 遍历到根,而第二个从根向后 up 遍历到叶子。假设当前 message_id 是 100(尽管 101 或 97 的值将具有相同的最终结果),以下查询 returns 所有相关消息(除 'Left out' 之外的所有消息):

with msgs(message_id, parent_id, message_content) as (
  select 101, 100, 'foo' from dual union all
  select 100, 97, 'bar' from dual union all
  select 99, null, 'Left out' from dual union all
  select 97, null, 'baz' from dual
), down as (
  select message_id start_id
       , CONNECT_BY_ROOT message_id curr_id
    from msgs
   where connect_by_isleaf = 1
   start with message_ID = 100
 connect by message_ID = prior parent_ID
) /* up */
 select level lvl
      , case message_id when curr_id then '*' end curr
      , msgs.* 
   from msgs, down
  start with message_ID = start_id
connect by prior message_ID = parent_ID
  order siblings by message_id;

down 查询中,我将其限制为 return 只有根消息节点 (connect_by_isleaf) 这样 start_id 将成为根消息,并且将当前 message_id 作为 curr_id 包含在 up 查询中以供参考,其中我包含一个列以用星号标记当前消息。