Как написать связанный рекурсивный подзапрос в sqlplus с несколькими таблицами для отслеживания узлов?

#sql #oracle #common-table-expression #recursive-query

#sql #Oracle #common-table-expression #рекурсивный запрос

Вопрос:

Я пытаюсь создать отчет, который сопоставляет нагрузки в цепи с их соответствующим источником питания (трансформатором).

Все устройства находятся в отдельных таблицах и взаимосвязаны в базе данных: нагрузки, коммутаторы, линии, провода, трансформаторы.

Для простоты я покажу пример, в котором нагрузка подключается к трансформатору напрямую только через коммутаторы:

Загрузить таблицу:

 LoadNumber, SectionNumber, BusNumber
100         54             3000
 

Переключить таблицу:

 SwitchNumber, FromSectionNumber, ToSectionNumber, State, BusNumber
1             54                 105              Closed 3000
2             105                106              Closed 3000
3             106                500              Open   3000
4             105                999              Closed 3000
5             999                700              Closed 3000
 

Таблица-трансформер:

 TransformerNumber, FromSectionNumber, ToSectionNumber, FromBus, ToBus
5000               800                700              2000     3000
5001               801                701              2000     3000
 

В приведенном выше примере трансформатор # 5000 подключен к нагрузке # 100 через подключение через переключатели в таблице и включен, потому что есть замкнутая цепь (замкнутые переключатели, соединяющие трансформатор и нагрузку вместе).

Я пытаюсь написать запрос, который может генерировать вывод, похожий на что-то вроде этого:

 LoadNumber, TransformerNumber
100         5000
 

Что означает, что нагрузка # 100 питается от трансформатора # 5000

Мне удалось успешно получить запрос, используя 1 таблицу (переключатели), чтобы найти преобразователь, с которым они связаны, но я немного запутался в том, как задействовать все таблицы, чтобы получить полное представление о сети.

То, что я получил до сих пор, было:

 WITH T3 AS
(SELECT SWITCHNAME, SWITCHNUMBER, PSEUDOSWITCH, FROMSECTIONNUMBER, TOSECTIONNUMBER, NORMALSWITCHINGDEVICESTATE, BUSNUMBER
FROM SWITCHINGDEVICE
WHERE UPPER(NORMALSWITCHINGDEVICESTATE) = 'CLOSED'
AND BUSNUMBER = 3484),
T2 AS
(SELECT TRANSFORMERNUMBER, TRANSFORMERNAME, FROMSECTIONNUMBER, TOSECTIONNUMBER, FROMBUSNUMBER, TOBUSNUMBER
FROM TRANSFORMER
WHERE TOBUSNUMBER = 3484),
T4 AS
(SELECT DEVICENUMBER, DEVICENAME, FROMSECTIONNUMBER, TOSECTIONNUMBER, FROMBUSREF, TOBUSREF
FROM PSA_SERIESREACTIVEDEVICE
WHERE TOBUSREF = 3484),
T5 AS
(SELECT LINENUMBER, LINENAME, FROMSECTIONNUMBER, TOSECTIONNUMBER, FROMBUSNUMBER, TOBUSNUMBER
FROM LINE
WHERE TOBUSNUMBER = 3484 AND FROMBUSNUMBER = 3484),
T1 AS
(SELECT A.BUSNUMBER, A.LOADNUMBER, A.LOADNAME, B.TRANSFORMERNUMBER, B.TRANSFORMERNAME
FROM LOADDEFINITION A, TRANSFORMER B
WHERE A.LOADNUMBER = 5572
AND A.BUSNUMBER = B.TOBUSNUMBER
---TEST LOAD
UNION ALL
SELECT T1.BUSNUMBER, T1.LOADNUMBER, T1.LOADNAME, T2.TRANSFORMERNUMBER, T2.TRANSFORMERNAME
FROM LOADDEFINITION T1, TRANSFORMER T2, SWITCHINGDEVICE T3, PSA_SERIESREACTIVEDEVICE T4, LINE T5, SWITCHINGDEVICE T6
WHERE
T1.LOADNUMBER = 5572 AND T1.BUSNUMBER = 3484
AND T2.TOBUSNUMBER = T1.BUSNUMBER
AND T3.BUSNUMBER = T1.BUSNUMBER
AND T4.TOBUSREF = T1.BUSNUMBER
AND T5.TOBUSNUMBER = T1.BUSNUMBER
AND T5.FROMBUSNUMBER = T5.TOBUSNUMBER
AND T3.BUSNUMBER = T2.TOBUSNUMBER
AND T4.TOBUSREF = T2.TOBUSNUMBER
AND T5.TOBUSNUMBER = T2.TOBUSNUMBER
AND T3.BUSNUMBER = T4.TOBUSREF
AND T5.TOBUSNUMBER = T3.BUSNUMBER
AND T5.TOBUSNUMBER = T4.TOBUSREF
AND T6.BUSNUMBER = T1.BUSNUMBER
---take into consideration downstream loops
AND ((T1.SECTIONNUMBER = T3.TOSECTIONNUMBER AND T1.SECTIONNUMBER = T6.TOSECTIONNUMBER)
    OR
     (T1.SECTIONNUMBER = T3.FROMSECTIONNUMBER AND T1.SECTIONNUMBER = T6.FROMSECTIONNUMBER))
AND (T3.FROMSECTIONNUMBER = T2.TOSECTIONNUMBER)
AND (T3.FROMSECTIONNUMBER = T6.TOSECTIONNUMBER)
AND T6.NORMALSWITCHINGDEVICESTATE = T3.NORMALSWITCHINGDEVICESTATE
)
SELECT T1.BUSNUMBER, T1.LOADNUMBER, T1.LOADNAME, T2.TRANSFORMERNUMBER, T2.TRANSFORMERNAME FROM T1, T2
 

Но вместо того, чтобы возвращать 1 результат, как я ожидал (поскольку я жестко запрограммировал одну загрузку), я получаю список, показывающий все преобразователи.

Представляя это с данными примера, результат выглядит примерно так:

 LoadNumber, TransformerNumber
100         5000
100         5001
 

Я некоторое время играл с этим и не уверен, какая часть этого запроса испорчена.

Редактировать:

Если бы я хотел написать запрос для получения желаемого результата с использованием примера набора данных, как бы это было сделано?

Что-то с логикой: выберите loadnumber, transformernumber, где load имеет прямое подключение к трансформатору через устройства с закрытым коммутатором?

Ответ №1:

В вашем упрощенном примере (вроде как я начал использовать ваши настоящие имена таблиц, но это исходные данные) вы можете получить все маршруты через несколько коммутаторов с:

 with rcte (rootsectionnumber, fromsectionnumber, tosectionnumber) as (
  select fromsectionnumber, fromsectionnumber, tosectionnumber
  from switchingdevice
  where normalswitchingdevicestate = 'CLOSED'
  union all
  select r.rootsectionnumber, sd.fromsectionnumber, sd.tosectionnumber
  from rcte r
  join switchingdevice sd on sd.fromsectionnumber = r.tosectionnumber
)
select rootsectionnumber, tosectionnumber from rcte;

ROOTSECTIONNUMBER TOSECTIONNUMBER
----------------- ---------------
               54             105
              105             106
              105             999
              999             700
               54             106
              105             500
               54             999
              105             700
               54             500
               54             700
 

один из которых имеет сквозной маршрут от раздела 54 до 700; и затем вы можете присоединить его к определению загрузки:

 with rcte (rootsectionnumber, fromsectionnumber, tosectionnumber) as (
  select fromsectionnumber, fromsectionnumber, tosectionnumber
  from switchingdevice
  where normalswitchingdevicestate = 'CLOSED'
  union all
  select r.rootsectionnumber, sd.fromsectionnumber, sd.tosectionnumber
  from rcte r
  join switchingdevice sd on sd.fromsectionnumber = r.tosectionnumber
)
select ld.loadnumber, t.transformernumber
from loaddefinition ld
join rcte r on r.rootsectionnumber = ld.sectionnumber
join transformer t on t.tosectionnumber = r.tosectionnumber
where ld.loadnumber = 100;

LOADNUMBER TRANSFORMERNUMBER
---------- -----------------
       100              5000
 

Или, если вам нужно включить busnumber в логику (основываясь на кратком взгляде на ваш более крупный запрос …):

 with rcte (rootsectionnumber, busnumber, fromsectionnumber, tosectionnumber) as (
  select fromsectionnumber, busnumber, fromsectionnumber, tosectionnumber
  from switchingdevice
  where normalswitchingdevicestate = 'CLOSED'
  union all
  select r.rootsectionnumber, r.busnumber, sd.fromsectionnumber, sd.tosectionnumber
  from rcte r
  join switchingdevice sd on sd.fromsectionnumber = r.tosectionnumber
  and sd.busnumber = r.busnumber
)
select ld.loadnumber, t.transformernumber
from loaddefinition ld
join rcte r on r.rootsectionnumber = ld.sectionnumber
and r.busnumber = ld.busnumber
join transformer t on t.tosectionnumber = r.tosectionnumber
and t.tobusnumber = r.busnumber
where ld.loadnumber = 100;

LOADNUMBER TRANSFORMERNUMBER
---------- -----------------
       100              5000
 

db<>скрипка

Добавление других ваших таблиц, очевидно, немного усложнит ситуацию, но не совсем ясно, как они все связаны.

Комментарии:

1. Я действительно ценю, что вы нашли время, чтобы просмотреть мою работу, я думаю, что то, что вы мне показали, является хорошей отправной точкой в том, как я должен структурировать свой запрос, я возьму то, что вы предоставили, и попытаюсь поиграть с ним, надеюсь, получить желаемый результат и обновить вопрос с решениемкак только я это выясню. Я пометил ваш ответ как принятый. Спасибо!

2. Один вопрос: для сопоставления узлов из других таблиц, которые будут рассмотрены в этом запросе, должны ли все остальные таблицы быть объединены в определении RTCE вместе с устройством переключения? Я думал, что каждую таблицу нужно будет определять отдельно, но, основываясь на том, как вы ее написали, я думаю, что можно было бы объединить все это в 1 определении. Я попробую.

3. Ваше окончательное решение, вероятно, не будет полезным для будущих посетителей. Но если вы попытаетесь адаптировать его для включения других таблиц и не сможете заставить это работать, вы можете задать новый вопрос с образцами данных для всех таблиц и сценариев, которые вам нужны. Это немного сложно расшифровать из попытки в этом вопросе * 😎

4. @BenCWang — это зависит от того, как они связаны на самом деле. Это может усложниться, если вы неоднократно переходите, скажем, от строки к трансформатору к строке к трансформатору, а не от строки к серии трансформаторов.

5. Опять же, боюсь, это действительно зависит от деталей. Вы можете сделать очень много с SQL и, как правило, должны возвращаться к PL / SQL только для невозможных вещей. Это звучит сложно, но возможно, исходя из того, что вы сказали — возможно, подойдет комбинация рекурсии и соединений, но, боюсь, на данный момент я не могу точно сказать.