将多行组合成一行,Oracle

时间:2010-04-22 11:07:36

标签: sql database oracle pivot one-to-many

我正在使用在Oracle中创建的数据库,并通过SDE在GIS软件中使用。我的一个同事将从这个数据库中做出一些统计数据,我无法找到合理的SQL查询来获取数据。

我有两个表,一个有注册,另一个有registrationdetails。这是一对多的关系,因此注册可以连接一个或多个细节(没有最大数量)。

  1. 表:注册
  2. RegistrationID          Date       TotLenght
    1                    01.01.2010        5
    2                    01.02.2010        15
    3                    05.02.2009        10
    

    2.table:RegistrationDetail

    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 个答案:

答案 0 :(得分:1)

如果详细记录的最大数量已修复且已知,则可以执行此操作。数字越大,查询编码越繁琐。这就是为什么大自然给了我们cut'n'paste。

以下查询使用了一些技巧。公用表表达式(又名Sub-Query Factoring)子句将查询封装在RegistrationDetail上,因此我们可以在多个位置轻松引用它。子查询使用分析函数ROW_NUMBER(),它允许我们识别RegistrationID组中的每个详细记录。这些功能都是在Oracle 9i中引入的,所以它们并不是新的,但很多人仍然不了解它们。

主查询使用外部联接将Registration表多次连接到子查询中的行。它加入了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>

显然,如果每个RegistrationID有四个详细记录,则需要四个外连接(以及投影中的四组列)。

修改

我刚刚重新阅读了你的问题并发现了“没有最大数量”的恐惧词。对不起,在这种情况下,你运气不好。使用可变数量的集合解决此问题的唯一方法是使用动态SQL,您已经有效地排除了这一点(因为您需要创建其他模式对象)。

编辑2

还有另一种解决方案,即提取数据和忘记布局。 Oracle允许我们在与标量一起的投影中声明内联游标,即嵌套的select语句。这传递了将输出显示给客户端工具的问题。

在这个版本中,我使用Oracle的内置XML功能来生成输出(基于这些天很多工具可以呈现XML)。 RegistrationDetails记录是名为REG_DETAILS的XMLElement中的组,它嵌套在每个注册记录中。

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
/

答案 1 :(得分:0)

在同一个查询中不能有多个具有相同名称的列 - oracle会将它们重命名为“Date_1”,“Date_2”等。有多行有什么问题?你是如何访问它的?

答案 2 :(得分:0)

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' ||       

    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 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

答案 3 :(得分:0)

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