2017-04-13 61 views
0

这是我的第一个问题,因此对任何礼仪错误表示歉意!如何使用SQL Oracle数据库返回特定的父/子结果

我有三个相关的表...

ID - 该表列出了所有记录
PARENT_CHILD_RELATIONSHIP可见ID - 此链接父记录与他们的孩子记录
信息 - 提供的所有记录

细节

的样本数据

Table ID     PARENT_CHILD_RELATIONSHIP DETAILS 
Columns KEY|PROPER_ID  PARENT_KEY|CHILD_KEY  KEY|FIELD 
     1|P1    1|NULL      5|A 
     2|P2    2|5      5|C 
     3|P3    2|6      6|A 
     4|P4    3|7      6|D 
     5|C1    4|8      7|B 
     6|C2    4|9      7|C 
     7|C3           8|A 
     8|C4           8|C 
     9|C5           9|B 
                 9|C 

这里是我的查询的一个简单的例子:

SELECT DISTINCT I.PROPER_ID, CHILD_ID_A.PROPER_ID, CHILD_ID_B.PROPER_ID 

FROM ID I     

LEFT OUTER JOIN PARENT_CHILD_RELATIONSHIP PCR_A ON PCR_A.PARENT_KEY = I.KEY 
LEFT OUTER JOIN DETAILS D_A ON D_A.KEY = PCR_A.CHILD_KEY 
AND D_A.FIELD = ('A')     
LEFT OUTER JOIN ID CHILD_ID_A ON CHILD_ID_A.KEY = DETAILS_A.KEY 

LEFT OUTER JOIN PARENT_CHILD_RELATIONSHIP PCR_B ON PCR_B.PARENT_KEY = I.KEY 
LEFT OUTER JOIN DETAILS D_B ON D_B.KEY = PCR_B.CHILD_KEY 
AND D_B.FIELD = ('B')     
LEFT OUTER JOIN ID CHILD_ID_B ON CHILD_ID_B.KEY = DETAILS_B.KEY 

WHERE I.PROPER_ID IN('1', '2', '3', '4') 

我想要的是返回所有记录中,其中(父)PROPER_ID或者是在第1列然后1,2,3,4,第2栏,我想回到孩子正确的记录ID (如果该记录在“详细信息”表中有'A')。对于第3列,我想要做与第2列相同的操作,但在DETAILS表中有一个带有'B'的子记录。

有4分可能的情况,我可以看到:
1.有0子记录与详细信息表中的“A”或“B” - 在这种情况下,我想返回一行只有家长Proper_ID并在随后的2栏中空白。
2.在细节表中有一个或多个带'A'的子记录 - 在这种情况下,我想返回与子记录一样多的行。
3.如上所述,但在细节表中只有'B'。
4.有'A'和'B'子记录 - 在这种情况下,如果每个记录中有一个,我想在同一行上重新显示所有数据。

电流输出

I.PROPER_ID | CHILD_ID_A.PROPER_ID | CHILD_ID_B.PROPER_ID 
P1   | NULL     | NULL 
P2   | C1     | NULL 
P2   | C2     | NULL 
P2   | NULL     | NULL 
P3   | NULL     | C3 
P3   | NULL     | NULL 
P4   | C4     | C5 
P4   | C4     | NULL 
P4   | NULL     | C5  
P4   | NULL     | NULL 

输出我想:

I.PROPER_ID | CHILD_ID_A.PROPER_ID | CHILD_ID_B.PROPER_ID 
P1   | NULL     | NULL 
P2   | C1     | NULL 
P2   | C2     | NULL 
P3   | NULL     | C3 
P4   | C4     | C5 

这甚至可能吗?我尝试了许多不同的变体,并尝试搜索其他示例,但尚未找到解决方案。

任何帮助将不胜感激!

+1

包括一些示例数据和预期输出你的问题将是有益的;以及当前查询的问题。 –

+0

谢谢@ alex-poole - 我已经添加了这些 - 希望不会太复杂 – AlexJ

+0

ID.PROPER_ID与ID.KEY或其他东西一样吗?您发布的查询不会始终使用别名,这有点令人困惑。父母/子女关系只有一级 - 没有孙子女? (不知道为什么你有一个单独的父/子表,而不是ID中的父列) –

回答

0

我认为你可以做你想做一个支点是什么(11g或更高版本;手动版有可能在更早的版本),这样的:

select * from (
    select p.proper_id as parent_id, c.proper_id as child_id, d.field, 
    row_number() over (partition by p.key, d.field order by c.key) as rn 
    from id p 
    join parent_child_relationship pcr on pcr.parent_key = p.key 
    left join id c on c.key = pcr.child_key 
    left join details d on d.key = c.key and d.field in ('A', 'B') 
    where p.proper_id in ('P1', 'P2', 'P3', 'P4') 
) 
pivot (max(child_id) as child for (field) in ('A' as a, 'B' as b)) 

row_number()在内部查询让它保持两个单独的行P2。如果父母有超过A的记录,他们将被配对,这可能是也可能不是你想要的,但目前还不清楚这是否会发生。

与样品数据,热膨胀系数:

with ID (KEY, PROPER_ID) as (
    select 1, 'P1' from dual 
    union all select 2, 'P2' from dual 
    union all select 3, 'P3' from dual 
    union all select 4, 'P4' from dual 
    union all select 5, 'C1' from dual 
    union all select 6, 'C2' from dual 
    union all select 7, 'C3' from dual 
    union all select 8, 'C4' from dual 
    union all select 9, 'C5' from dual 
), PARENT_CHILD_RELATIONSHIP (PARENT_KEY, CHILD_KEY) as (
    select 1, null from dual 
    union all select 2, 5 from dual 
    union all select 2, 6 from dual 
    union all select 3, 7 from dual 
    union all select 4, 8 from dual 
    union all select 4, 9 from dual 
), DETAILS (KEY, FIELD) as (
    select 5, 'A' from dual 
    union all select 6, 'A' from dual 
    union all select 7, 'B' from dual 
    union all select 8, 'A' from dual 
    union all select 9, 'B' from dual 
) 
select parent_id, a_child as child_a_id, b_child as child_b_id 
from (
    select p.proper_id as parent_id, c.proper_id as child_id, d.field, 
    row_number() over (partition by p.key, d.field order by c.key) as rn 
    from id p 
    join parent_child_relationship pcr on pcr.parent_key = p.key 
    left join id c on c.key = pcr.child_key 
    left join details d on d.key = c.key and d.field in ('A', 'B') 
    where p.proper_id in ('P1', 'P2', 'P3', 'P4') 
) 
pivot (max(child_id) as child for (field) in ('A' as a, 'B' as b)) 
order by 1, 2, 3; 

产生:

PARENT_ID CHILD_A_ID CHILD_B_ID 
--------- ---------- ---------- 
P1        
P2  C1     
P2  C2     
P3     C3   
P4  C4   C5   

如果您使用的是较早的版本不支持,你可以做pivot更明确的同样的事情:

select parent_id, 
    max(case when field = 'A' then child_id end) as child_a_id, 
    max(case when field = 'B' then child_id end) as child_b_id 
from (
    select p.proper_id as parent_id, c.proper_id as child_id, d.field, 
    row_number() over (partition by p.key, d.field order by c.key) as rn 
    from id p 
    join parent_child_relationship pcr on pcr.parent_key = p.key 
    left join id c on c.key = pcr.child_key 
    left join details d on d.key = c.key and d.field in ('A', 'B') 
    where p.proper_id in ('P1', 'P2', 'P3', 'P4') 
) 
group by parent_id, rn 
order by 1, 2, 3; 
+0

非常感谢您的回答,如果我正在运行9i,是否有任何建议可以提供给手动版本的数据透视表? – AlexJ

+0

@AlexJ - 我在最后添加了手动版本。无论如何,'pivot'语法在引擎盖下做同样的事情。 –

+0

我会将此标记为答案,非常感谢您的帮助。如果你有机会,你是否可以编辑添加where语句(WHERE I.PROPER_ID IN('1','2','3','4'))? – AlexJ

相关问题