Объединяя несколько строк в одну строку, Oracle - PullRequest
1 голос
/ 22 апреля 2010

Я работаю с базой данных, которая создана в Oracle и используется в ГИС-программном обеспечении через SDE. Один из моих коллег собирается сделать статистику из этой базы данных, и я не в состоянии найти разумный SQL-запрос для получения данных.

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

  1. Таблица: Регистрация
RegistrationID          Date       TotLenght
1                    01.01.2010        5
2                    01.02.2010        15
3                    05.02.2009        10

2.таблица: регистрацияДеталь

DetailID     RegistrationID   Owner      Type      Distance
1                  1           TD          UB          1,5
2                  1           AB          US          2
3                  1           TD          UQ          4
4                  2           AB          UQ         13
5                  2           AB          UR         13,1
6                  3           TD          US          5

Я хочу, чтобы результирующий выбор был примерно таким:

RegistrationID          Date       TotLenght DetailID     RegistrationID   Owner     Type      Distance  DetailID     RegistrationID   Owner      Type      Distance  DetailID     RegistrationID   Owner      Type      Distance
1                    01.01.2010        5         1              1           TD        UB          1,5          2               1          AB        US          2         3                  1              TD          UQ          4
2                    01.02.2010        15        4              2           AB        UQ         13            5               2          AB        UR         13,1
3                    05.02.2009        10        6              3           TD        US          5

При обычном объединении я получаю по одной строке на каждую регистрацию и каждую деталь. Кто-нибудь может мне с этим помочь? У меня нет прав администратора для базы данных, поэтому я не могу создавать таблицы или переменные. Если это возможно, я мог бы скопировать таблицы в Access.

Ответы [ 4 ]

1 голос
/ 22 апреля 2010

Если максимальное количество записей сведений фиксировано и известно, то это можно сделать. Чем больше число, тем труднее запросить код. Вот почему природа дала нам пасту.

В следующем запросе используется несколько хитростей. Предложение 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
/
0 голосов
/ 15 апреля 2015
SELECT   
wo_h.event_perfno_i AS WO,
wo_h.ata_chapter,
    wo_h.created_by AS WorkOrderCreator,
    wo_h.issue_date As Work_Order_IssueDate, 
    wo_h.ac_registr As WorkOrderACRegister,
    wo_h.state As WorkOrderState,

('Created By:'||wsl.workstep_sign||'  On') As Description,

wsl.workstep_date,




listagg('Action Performed By,' ||woa.mutator||'At date' || woa.action_date|| '.'|| woa.text,'.. ')   WITHIN GROUP ( ORDER BY woa.text)   
   FROM workstep_link wsl
 join wo_header wo_h on wsl.event_perfno_i=wo_h.event_perfno_i
  join  wo_text_action woa on wsl.workstep_linkno_i=woa.workstep_linkno_i

WHERE
wo_h.state = 'O'


      AND wo_h.event_perfno_i = '5690136'
     AND wo_h.ac_registr = 'AEC'
    GROUP BY wo_h.event_perfno_i, wo_h.ata_chapter, wo_h.created_by,wo_h.issue_date,wo_h.ac_registr,wo_h.state,wsl.workstep_date,
    wsl.workstep_time,
    wsl.workstep_sign
0 голосов
/ 15 апреля 2015
SELECT   
wo_h.event_perfno_i AS WO,
wo_h.ata_chapter,
    wo_h.created_by AS WorkOrderCreator,
    wo_h.issue_date As Work_Order_IssueDate, 
    wo_h.ac_registr As WorkOrderACRegister,
    wo_h.state As WorkOrderState,
    ('Created By:'||wsl.workstep_sign||'  On') As Description,
    wsl.workstep_date,
     listagg('Action Performed By,' ||woa.mutator||'At date' ||       

<div class="snippet" data-lang="js" data-hide="false">
<div class="snippet-code">
<pre class="snippet-code-html lang-html prettyprint-override"><code>    SELECT   
    wo_h.event_perfno_i AS WO,
    wo_h.ata_chapter,
        wo_h.created_by AS WorkOrderCreator,
    	wo_h.issue_date As Work_Order_IssueDate, 
    	wo_h.ac_registr As WorkOrderACRegister,
    	wo_h.state As WorkOrderState,

    ('Created By:'||wsl.workstep_sign||'  On') As Description,

    wsl.workstep_date,




    listagg('Action Performed By,' ||woa.mutator||'At date' || woa.action_date|| '.'|| woa.text,'.. ')   WITHIN GROUP ( ORDER BY woa.text)   
       FROM workstep_link wsl
     join wo_header wo_h on wsl.event_perfno_i=wo_h.event_perfno_i
      join  wo_text_action woa on wsl.workstep_linkno_i=woa.workstep_linkno_i

    WHERE
    wo_h.state = 'O'
 

          AND wo_h.event_perfno_i = '5690136'
         AND wo_h.ac_registr = 'AEC'
        GROUP BY wo_h.event_perfno_i, wo_h.ata_chapter, wo_h.created_by,wo_h.issue_date,wo_h.ac_registr,wo_h.state,wsl.workstep_date,
        wsl.workstep_time,
        wsl.workstep_sign
    
    
woa.action_date ||'' ||woa.text, '..') WITHIN GROUP (ORDER BY woa.text) FROM workstep_link wsl присоединиться к wo_header wo_h на wsl.event_perfno_i = wo_h.event_perfno_i присоединиться к wo_text_action woa на wsl.workstep_linkno_i = woeh. whi.tep'AND wo_h.event_perfno_i =' 5690136 'AND wo_h.ac_registr =' AEC 'GROUP BY wo_h.event_perfno_i, wo_h.ata_chapter, wo_h.created_by, wo_h.issue_date, wo_h.ac_registr, wo_l.tete, wsl.workstep_sign
0 голосов
/ 22 апреля 2010

Вы не можете иметь несколько столбцов с одним и тем же именем в одном запросе - oracle переименует их в «Date_1», «Date_2» и т. Д. Что плохого в том, чтобы иметь несколько строк? Как вы к нему обращаетесь?

...