Если максимальное количество записей сведений фиксировано и известно, то это можно сделать. Чем больше число, тем труднее запросить код. Вот почему природа дала нам пасту.
В следующем запросе используется несколько хитростей. Предложение Common Table Expression (также известное как Sub-Query Factoring) инкапсулирует запрос в RegistrationDetail, поэтому мы можем легко ссылаться на него в нескольких местах. Подзапрос использует аналитическую функцию ROW_NUMBER (), которая позволяет нам идентифицировать каждую запись сведений в группе RegistrationID. Обе эти функции были введены в Oracle 9i, поэтому они не новы, но многие люди до сих пор не знают о них.
Основной запрос использует внешние соединения для многократного подключения таблицы регистрации к строкам подзапроса. Он присоединяется к RegistrationID и производному DetNo.
SQL> with dets as
2 ( select
3 registrationid
4 , owner
5 , type
6 , distance
7 , detailid
8 , row_number() over (partition by registrationid
9 order by detailid) as detno
10 from registrationdetail )
11 select
12 reg.registrationid
13 , reg.somedate
14 , reg.totlength
15 , det1.detailid as detId1
16 , det1.owner as owner1
17 , det1.type as type1
18 , det1.distance as distance1
19 , det2.detailid as detId2
20 , det2.owner as owner2
21 , det2.type as type2
22 , det2.distance as distance2
23 , det3.detailid as detId3
24 , det3.owner as owner3
25 , det3.type as type3
26 , det3.distance as distance3
27 from registration reg
28 left join dets det1 on ( reg.registrationid = det1.registrationid
29 and det1.detno = 1 )
30 left join dets det2 on ( reg.registrationid = det2.registrationid
31 and det2.detno = 2 )
32 left join dets det3 on ( reg.registrationid = det3.registrationid
33 and det3.detno = 3 )
34 order by reg.registrationid
35 /
REGISTRATIONID SOMEDATE TOTLENGTH DETID1 OW TY DISTANCE1 DETID2 OW TY DISTANCE2 DETID3 OW TY DISTANCE3
-------------- --------- ---------- ---------- -- -- ---------- ---------- -- -- ---------- ---------- -- -- ----------
1 01-JAN-10 5 1 TD UB 1.5 2 AB US 2 3 TD UQ 4
2 01-FEB-10 15 4 AB UQ 13 5 AB UR 13.1
3 05-FEB-09 10 6 TD US 5
SQL>
Очевидно, что если у вас есть четыре подробных записи для каждого регистрационного идентификатора, вам понадобятся четыре из этих внешних соединений (и четыре набора столбцов в проекции).
редактировать
Я только что перечитал ваш вопрос и заметил ужасные слова «Нет максимального числа». Извините, в таком случае вам не повезло. Единственный способ решения этой проблемы с переменным числом наборов - это динамический SQL, который вы фактически исключили (поскольку вам нужно было бы создавать дополнительные объекты схемы).
редактировать 2
Существует еще одно решение, которое заключается в извлечении данных и забывании макета. Oracle позволяет нам объявлять встроенные курсоры, то есть вложенные операторы select
, в проекции вместе со скалярами. Это передает проблему отображения вывода клиентскому инструменту.
В этой версии я использую встроенную в Oracle функциональность XML для получения выходных данных (исходя из того, что многие инструменты могут визуализировать XML в наши дни). Записи RegistrationDetails - это группа в элементе XMLE с именем REG_DETAILS, который вложен в каждую запись регистрации.
with dets as
( select
registrationid
, owner
, type
, distance
, detailid
, row_number() over (partition by registrationid
order by detailid) as detno
from registrationdetail )
select
xmlelement("AllRegistrations"
, xmlagg(
xmlelement("Registration"
, xmlforest( reg.registrationid
, reg.somedate
, reg.totlength
, ( select xmlagg(
xmlelement("RegDetail"
, xmlforest(dets.detailid
, dets.owner
, dets.type
, dets.distance
, dets.detno
)
)
)
from dets
where reg.registrationid = dets.registrationid
) as "RegDetails"
)
)
)
)
from registration reg
order by reg.registrationid
/