【问题标题】:Return data from multiple child tables in same row从同一行中的多个子表返回数据
【发布时间】:2017-03-26 08:09:12
【问题描述】:

我有一些通过外键关联的表,我需要从中获取数据,它们的结构类似于:

    Table A                Intermediate A              Child A
| id |   Data          | idTableA | idChildA        | id | Child A
| 1  | 'Data 1'        | 1        | 1               | 1  | 'Child 1'
| 2  | 'Data 2'        | 1        | 2               | 2  | 'Child 2'
| 3  | 'Data 3'        | 1        | 3               | 3  | 'Child 3'
                       | 2        | 4               (...)
                       | 2        | 5
                       | 3        | 6
                       | 3        | 6

                           Intermediate B              Child B
                       | idTableA | idChildB        | id | Child B
                       | 1        | 4               | 4  | 'Child 1'
                       | 1        | 5               | 5  | 'Child 2'
                       | 1        | 6               | 6  | 'Child 3'
                       | 2        | 6               (...)
                       | 2        | 7
                       | 3        | 8
                       | 3        | 9

我要做的是从两个子表中获取与中间表中的Table A 键一致但不合并数据的所有记录。像这样的:

                  Result
|idTableA|ChildA  |Child B |
|1       |'Child1'|null    |
|1       |'Child2'|null    |
|1       |'Child3'|null    |
|1       |null    |'Child4'|
|1       |null    |'Child5'|
|1       |null    |'Child6'|
|2       |'Child4'|null    |
|2       |'Child5'|null    |
|2       |null    |'Child6'|
|2       |null    |'Child7'|
(...)

我一直在申请中间表,然后从那里申请子表,但未能成功地从我应该获得空值的子表中检索混合数据。

有什么想法吗?

【问题讨论】:

  • 您是否还想在任一子表中包含表 A 中具有 no 相关行的行?

标签: sql postgresql join union union-all


【解决方案1】:

您应该从单独的子表中选择行,然后在这两个子句之间执行UNION,为另一个子表中的字段指定NULL

SELECT main1.id AS idTableA, ca.childA, NULL::text AS childB
FROM tableA main1
JOIN intermediateA ia ON main1.id = ia.idTableA
JOIN childA ca ON ca.id = ia.idChildA

UNION

SELECT main2.id AS idTableA, NULL, cb.childB
FROM tableA main2
JOIN intermediateB ib ON main2.id = ib.idTableA
JOIN childB cb ON cb.id = ib.idChildB

ORDER BY 1, 2, 3;

【讨论】:

  • 在实现你的查询后终于可以解决这个问题了。非常感谢!
【解决方案2】:

What @Patrick says.
但除非你...

  • 想要包含表 A 中的行,但在任一子表中都没有相关行
  • 或者您想消除表 A 中不存在的 idTableA 值(不能使用 FK 约束)

...您根本不需要在查询中包含表 A。 (否则您需要LEFT JOIN。)

SELECT ia.idTableA, ca.childA, NULL::text AS childB
FROM   intermediateA ia
JOIN   childA ca ON ca.id = ia.idChildA

UNION ALL  -- ! 

SELECT ib.idTableA, NULL, cb.childB
FROM   intermediateB ib
JOIN   childB cb ON cb.id = ib.idChildB

ORDER   BY 1, 2, 3;

然后制作UNION ALL。更便宜,而且您不想在此处尝试折叠重复项。

【讨论】:

  • 我猜你正在使用UNION ALL 就像一个优化器提示(“请继续,这里没什么可看的”)但你是否认为人类读者也需要取消选择这个?我将UNION ALL 视为创建具有重复行的结果集的一种方式,但我从不想这样做!所以我总是使用UNION。如果这很昂贵,那么我值得,为我构建一个更智能的优化器......但在你这样做之前,向我证明 UNION ALL 是“更便宜”。
  • @onedaywhen:UNION ALL 显然更快,你自己试试吧。更重要的是,如果不应该消除重复行,UNION错误,简单明了。因为你喜欢它看起来的样子而坚持它是……好吧,哪儿也不去。这就像坚持一个简单的JOIN,其中逻辑需要LEFT JOIN,只是因为它在人眼上更容易。即使它对当前数据集没有影响,它也是一个等待发生的错误。如果Child A 列未定义UNIQUE(错误地)怎么办?
  • 这不是关于化妆品哈哈,而是关于关系模型。 RM 中没有重复的元组,即使在派生关系(查询结果)中也是如此,所以我在 SQL 中没有UNION ALL 的用例。 RM 中没有空值,所以我在 SQL 中没有 LEFT JOIN 的用例。
  • @onedaywhen:LEFT JOIN 可以在您的模型中生成没有任何 NULL 的 NULL 值。
  • 确实,这就是为什么应该避免使用LEFT JOIN(或者如果使用它,它会产生的空值不会投影到结果中)。
猜你喜欢
  • 2015-02-18
  • 2021-03-30
  • 1970-01-01
  • 2020-09-24
  • 2020-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多