【问题标题】:How to return specific Parent/Child results with SQL Oracle database如何使用 SQL Oracle 数据库返回特定的父/子结果
【发布时间】:2017-04-13 10:23:26
【问题描述】:

这是我的第一个问题,如有任何礼仪错误,我们深表歉意!

我有三个相关的表...

ID - 此表提供所有记录的可见 ID
PARENT_CHILD_RELATIONSHIP - 这会将父记录与其子记录链接
DETAILS - 提供所有记录的详细信息

样本数据

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

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

我可以看到 4 种可能的情况:
1.详细信息表中有 0 条带有“A”或“B”的子记录 - 在这种情况下,我想返回一行,其中仅包含 Parent Proper_ID 和后续 2 列中的空白。
2.详细信息表中有 1 个或多个带有“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

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

任何帮助将不胜感激!

【问题讨论】:

  • 在您的问题中包含一些示例数据和预期输出会有所帮助;以及您当前查询的问题所在。
  • 谢谢@alex-poole - 我已经添加了这些 - 希望不会太复杂
  • ID.PROPER_ID 是否与 ID.KEY 相同或其他?您发布的查询也没有始终使用别名,这有点令人困惑。是否只有一层亲子关系——没有孙子? (不知道为什么你有一个单独的父/子表,而不仅仅是 ID 中的父列......)
  • 它们是两个不同的字段,PROPER_ID 仅存在于 ID 表中 - 也许值得我在示例数据中澄清,以便它显示正确的表内容?只有 1 级父/子。
  • 是的,并确保查询和当前输出与样本数据匹配。真的在寻找an MCVE,因为我不确定我是否理解你想要做的事情的描述。

标签: sql oracle


【解决方案1】:

我认为您可以使用支点(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 B 记录,他们将配对,这可能是也可能不是您想要的,但目前尚不清楚这是否会发生。

将您的样本数据作为 CTE:

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;

【讨论】:

  • 非常感谢您的回答,如果我正在运行 9i,您可以为枢轴的手动版本提供任何建议吗?
  • @AlexJ - 我在最后添加了手动版本。无论如何,pivot 语法在底层做同样的事情。
  • 我会将其标记为已回答,非常感谢您的帮助。如果你有机会,你能编辑添加 where 语句(WHERE I.PROPER_ID IN('1', '2', '3', '4'))吗?
  • 好的,忘记了,虽然这些不是您数据中的值 *8-) 我只是在猜测,但您实际上可能只是想基于所有 parent_key 值,idprc 之间的内部连接无论如何都会这样做 - 取决于您的值列表是否应该涵盖所有这些,您可能正在使用它们的一小部分。
  • 好点 :) 再次感谢您的帮助!下次我也会更好地了解如何提出问题,非常有用的建议。
猜你喜欢
  • 1970-01-01
  • 2018-05-11
  • 2014-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多