我正在使用在Oracle中创建的数据库,并通过SDE在GIS软件中使用。我的一个同事将从这个数据库中做出一些统计数据,我无法找到合理的SQL查询来获取数据。
我有两个表,一个有注册,另一个有registrationdetails。这是一对多的关系,因此注册可以连接一个或多个细节(没有最大数量)。
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中。
答案 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