#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
Добавление других ваших таблиц, очевидно, немного усложнит ситуацию, но не совсем ясно, как они все связаны.
Комментарии:
1. Я действительно ценю, что вы нашли время, чтобы просмотреть мою работу, я думаю, что то, что вы мне показали, является хорошей отправной точкой в том, как я должен структурировать свой запрос, я возьму то, что вы предоставили, и попытаюсь поиграть с ним, надеюсь, получить желаемый результат и обновить вопрос с решениемкак только я это выясню. Я пометил ваш ответ как принятый. Спасибо!
2. Один вопрос: для сопоставления узлов из других таблиц, которые будут рассмотрены в этом запросе, должны ли все остальные таблицы быть объединены в определении RTCE вместе с устройством переключения? Я думал, что каждую таблицу нужно будет определять отдельно, но, основываясь на том, как вы ее написали, я думаю, что можно было бы объединить все это в 1 определении. Я попробую.
3. Ваше окончательное решение, вероятно, не будет полезным для будущих посетителей. Но если вы попытаетесь адаптировать его для включения других таблиц и не сможете заставить это работать, вы можете задать новый вопрос с образцами данных для всех таблиц и сценариев, которые вам нужны. Это немного сложно расшифровать из попытки в этом вопросе * 😎
4. @BenCWang — это зависит от того, как они связаны на самом деле. Это может усложниться, если вы неоднократно переходите, скажем, от строки к трансформатору к строке к трансформатору, а не от строки к серии трансформаторов.
5. Опять же, боюсь, это действительно зависит от деталей. Вы можете сделать очень много с SQL и, как правило, должны возвращаться к PL / SQL только для невозможных вещей. Это звучит сложно, но возможно, исходя из того, что вы сказали — возможно, подойдет комбинация рекурсии и соединений, но, боюсь, на данный момент я не могу точно сказать.