Одна трудность здесь в том, что у вас есть входные данные в трех столбцах, а вы хотите получить результаты в трех столбцах. Если вы не хотите использовать динамический SQL (который является отдельной темой, продвинутой техникой, которая в большинстве случаев также является плохой практикой и не имеет ничего общего с вашим вопросом о комбинаторике), вам придется жестко кодировать число (иимена) столбцов в запросе.
Вы можете представить входные данные в строках, а не в столбцах, и запросить результат в формате
row_num col_num val
------- ------- ---
1 1 1
1 2 -
1 3 -
(это имитирует только ваш первый выводстрока) - и аналогично для всех других строк - и тогда вам НЕ нужно будет жестко кодировать количество столбцов в запросе;затем вы можете легко адаптировать приведенный ниже код для решения этой более общей проблемы.
Я использую SYS_CONNECT_BY_PATH
ниже, что ограничивает количество столбцов (и длину значений в каждом столбце во входных данных);этого можно избежать, но написание запроса таким способом - весело.
Я предположил, что тире -
в желаемом выводе означает NULL
;если вы действительно хотите показывать тире, используйте NVL(..., -)
в последнем предложении SELECT
.
with
t (col1, col2, col3) as (
select 1 as col1, 2 as col2, 3 as col3 from dual
)
, prep (pth) as (
select sys_connect_by_path(val, '/') || '/'
from t
unpivot (val for col in (col1, col2, col3))
connect by nocycle prior col is not null
)
select to_number(substr(pth, instr(pth, '/', 1, 1) + 1,
instr(pth, '/', 1, 2) - instr(pth, '/', 1, 1) - 1)) col1,
to_number(substr(pth, instr(pth, '/', 1, 2) + 1,
instr(pth, '/', 1, 3) - instr(pth, '/', 1, 2) - 1)) col2,
to_number(substr(pth, instr(pth, '/', 1, 3) + 1,
instr(pth, '/', 1, 4) - instr(pth, '/', 1, 3) - 1)) col3
from prep
order by col1 nulls first, col2 nulls first, col3 nulls first
;
Вывод:
COL1 COL2 COL3
----- ----- -----
1
1 2
1 2 3
1 3
1 3 2
2
2 1
2 1 3
2 3
2 3 1
3
3 1
3 1 2
3 2
3 2 1