2016-11-28 11 views
3

Я отчасти новичок в более сложных вопросах PLSQL, поэтому, надеюсь, кто-то может мне помочь.Рекурсивный запрос в Oracle

Проблема: У меня есть таблица с сообщениями, отправленными между администратором и пользователями. В таблице есть message_parent с FK в одно и то же поле 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, мне трудно понять это.

+0

Какую версию Oracle вы используете? –

+0

12c Стандартная версия – taurijuhkam

ответ

5

В 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 with и connect 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 
+0

опечатка? Я думаю, вы имеете в виду: 'connect by previous MESSAGE_id = parent_id;' ?? – Ditto

+0

@ Ditto: да, спасибо. –

+1

Это в основном похоже на трюк, но: что, если я не знаю идентификатора корня разговора? Большую часть времени он фактически работает в обратном направлении -> пользователь выбирает сообщение, и мне нужно показывать предыдущие сообщения. Поэтому я знаю последнее или одно из среднего message_id, и мне нужно идти назад. Если я заменил start с текущим идентификатором сообщения, я не получу предыдущие сообщения, а те, которые были после текущего сообщения. E, g Я знаю, что message_id 100 - это бар, как мне добраться до mnessage_id 97, baz – taurijuhkam

1

Чтобы получить весь контекст сообщения на основе от одного message_id, вы можете использовать два иерархических запроса. Один идет по дереву сообщений от текущего сообщения down к корню, а второй возвращается up от корня до листьев. Если предположить, что текущий MESSAGE_ID является 100 (хотя значения 101 или 97 будет иметь тот же конечный результат), следующий запрос возвращает все сообщения, относящиеся к (все, кроме «Вышедшие»):

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 запросе I» (connect_by_isleaf), так что start_id будет корневым сообщением и включил текущий message_id как curr_id для ссылки в запросе up, где я включил столбец для маркировки текущего сообщения звездочкой ,