从同一行

时间:2016-11-12 02:47:29

标签: sql postgresql join union union-all

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

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

我一直在申请中间表,从那里到子表只是从子表中检索混合数据失败,我应该得到空值。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您应该从单独的子表中选择行,然后在这两个子句之间执行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;

答案 1 :(得分:1)

What @Patrick says.
But unless you ...

  • want to include rows from Table A with no related row in either child table
  • or you want to eliminate idTableA values not present in Table A (not possible with FK constraint)

... you don't need to include Table A in the query at all. (Else you need 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;

And make that UNION ALL. Cheaper, and you do not want to attempt to fold duplicates here.