【问题标题】:Recursive query in OracleOracle中的递归查询
【发布时间】:2017-04-12 08:01:27
【问题描述】:

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

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

示例 消息表:

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

因此,选择 message_content 的正确查询应该返回“baz”、“bar”和“foo”,而不是“Left out”(因为 baz 是原始消息)。 如果有例如,这将很简单只有两条消息可以捆绑在一起,或者例如一个 thread_id 列,它将链接同一“线程”中的所有消息,但随着 parent_id 的不断变化,我无法弄清楚。

【问题讨论】:

  • 您使用的是什么版本的 Oracle?
  • 12c标准版

标签: sql oracle oracle12c recursive-query connect-by


【解决方案1】:

要基于单个 message_id 获取整个消息上下文,您可以使用两个分层查询。一个将消息树从当前消息down 遍历到根,而第二个将up 从根返回到叶子。假设当前 message_id 为 100(尽管 101 或 97 的值将具有相同的最终结果),以下查询将返回所有相关消息(除“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 查询中,我将其限制为仅返回根消息节点 (connect_by_isleaf),这样 start_id 将成为根消息,并将当前 message_id 包含为 curr_id 以供参考up 查询我在其中包含一列以用星号标记当前消息。

【讨论】:

    【解决方案2】:

    在 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
    

    【讨论】:

    • 错字?我想你的意思是:connect by prior MESSAGE_id = parent_id; ??
    • 这似乎可以解决问题,但是:如果我不知道对话根的 ID 怎么办?大多数情况下,它实际上是向后工作的-> 用户选择了一条消息,我需要显示以前的消息。所以我知道中间message_id的最后一个或一个,我需要向后退。如果我用当前消息 id 替换 start,我不会得到以前的消息,而是当前消息之后的消息。 E,g 我知道 message_id 100 是 bar,我如何到达 mnessage_id 97,baz
    • 请问您为什么在第二个查询中使用 message_id 100 而不是 101
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-27
    • 2013-03-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-11
    • 2019-11-24
    相关资源
    最近更新 更多