在几张桌子上完全加入

时间:2014-07-29 11:29:19

标签: sql sql-server join outer-join

我有一个项目清单,按存款,库存,采购订单,销售订单,消费或生产预测等。我想设置一个查询每个项目给我所有这些信息,存款存款。显然,并不是说每个项目都有这些信息。

例如,考虑以下表格:

T1
|    REF |
|--------|
|      1 |

T2
|    REF |  DEPOT |
|--------|--------|
|      1 |      A |
|      1 |      B |

T3
|    REF |  DEPOT |
|--------|--------|
|      1 |      A |
|      1 |      C |

T4
|    REF |  DEPOT |
|--------|--------|
|      1 |      B |
|      1 |      C |
|      1 |      D |

如果我只采用前三个表(刚开始),我找不到比:

SELECT T1.ref AS T1ref
  , T2.ref AS T2ref, T2.depot AS T2depot
  , T3.ref AS T3ref, T3.depot AS T3depot
FROM T1
  LEFT JOIN T2
    ON T2.ref = T1.ref
  FULL JOIN T3
    ON T3.ref = T1.ref
    AND T3.depot = T2.depot

输出:

|  T1REF |  T2REF | T2DEPOT |  T3REF | T3DEPOT |
|--------|--------|---------|--------|---------|
|      1 |      1 |       A |      1 |       A |
|      1 |      1 |       B | (null) |  (null) |
| (null) | (null) |  (null) |      1 |       C |

我想要的是什么:

|  T1REF |  T2REF | T2DEPOT |  T3REF | T3DEPOT |
|--------|--------|---------|--------|---------|
|      1 |      1 |       A |      1 |       A |
|      1 |      1 |       B | (null) |  (null) |
|      1 | (null) |  (null) |      1 |       C |

必须有一个干净的方法来做到这一点,但我没有找到任何东西。而且很难在此找到材料。

有人有提示吗?

sqlfiddle:http://sqlfiddle.com/#!3/19014/2

谢谢你, 大卫。

修改
用T4:

|  T1REF |  T2REF | T2DEPOT |  T3REF | T3DEPOT |  T4REF | T4DEPOT |
|--------|--------|---------|--------|---------|--------|---------|
|      1 |      1 |       A |      1 |       A | (null) |  (null) |
|      1 |      1 |       B | (null) |  (null) |      1 |       B |
|      1 | (null) |  (null) |      1 |       C |      1 |       C |
|      1 | (null) |  (null) | (null) |  (null) |      1 |       D |

我应该用更好的名字命名我的表:T1 =项目,T2 =股票,T3 =购买,T4 =卖出。因此,T1将始终拥有所有参考,以及我需要的许多其他信息。

3 个答案:

答案 0 :(得分:1)

您可以使用coalesce()修正您的特定查询:

SELECT coalesce(T1.ref, t2.ref, t3.ref) AS T1ref

但是,我发现使用我关注的列表和组合更容易,而不是使用full outer join。在这种情况下,您似乎关心所有表中的t1.refdepots。也许这更接近你真正想做的事情:

SELECT t1ref.ref,
       T2.ref AS T2ref, T2.depot AS T2depot,
       T3.ref AS T3ref, T3.depot AS T3depot
FROM (select ref from T1 union
      select ref from T2 union
      select ref from T3
     ) t1ref cross join
     (select depot from T2 union
      select depot from t3
     ) d LEFT JOIN T2
     ON T2.ref = T1ref.ref and
        t2.depot = d.depot LEFT JOIN
     T3
     ON T3.ref = T1ref.ref AND
        T3.depot = d.depot --OR T2.depot IS NULL)

答案 1 :(得分:0)

Gordon Linoff所述的所有4个表和Coalesce的示例

;with[T1]([REF])as(
       select * from (values(1),(2))[A]([REF])
),
[T2]([REF],[DEPOT])as(
       select*from(values
             (1,'A'),
             (1,'B'),
             (1,'E')
       )[a]([REF],[DEPOT])
),
[T3]([REF],[DEPOT])as(
       select*from(values
             (1,'A'),
             (1,'C')
       )[a]([REF],[DEPOT])
),
[T4]([REF],[DEPOT])as(
       select*from(values
             (1,'B'),
             (1,'C'),
             (1,'D'),
             (1,'E')
       )[a]([REF],[DEPOT])
)

select
*
from [T1]
outer apply (
      select
            T2.REF T2REF,
            T2.DEPOT T2DEPOT,
            T3.REF T3REF,
            T3.DEPOT T3DEPOT,
            T4.REF T4REF,
            T4.DEPOT T4DEPOT
      from T2
      full outer join T3 on
            T2.REF = T3.REF and
            T2.DEPOT = T3.DEPOT
      full outer join T4 on   
            COALESCE(T3.REF,T2.REF) = T4.REF and
            COALESCE(T3.DEPOT,T2.DEPOT) = T4.DEPOT
      where
        COALESCE(T2.REF,T3.REF,T4.REF) = T1.REF
) TR

答案 2 :(得分:0)

在你的帮助下,我发现如果我忘记了一段时间的项目信息(表T1),我几乎可以获得我想要的东西:

SELECT *
FROM T2
  FULL JOIN T3
    ON T3.ref = T2.ref
    AND T3.depot = T2.depot
  FULL JOIN T4
    ON (
      T4.ref = T2.ref
      AND T4.depot = T2.depot
    )
    OR (
      T4.ref = T3.ref
      AND T4.depot = T3.depot
    )

它给出了:

|  T2REF | T2DEPOT |  T3REF | T3DEPOT |  T4REF | T4DEPOT |
|--------|---------|--------|---------|--------|---------|
|      1 |       A |      1 |       A | (null) |  (null) |
|      1 |       B | (null) |  (null) |      1 |       B |
| (null) |  (null) |      1 |       C |      1 |       C |
| (null) |  (null) | (null) |  (null) |      1 |       D |

之后我必须得到T1信息:

SELECT *
FROM T2
  FULL JOIN T3
    ON T3.ref = T2.ref
    AND T3.depot = T2.depot
  FULL JOIN T4
    ON (
      T4.ref = T2.ref
      AND T4.depot = T2.depot
    )
    OR (
      T4.ref = T3.ref
      AND T4.depot = T3.depot
    )
  INNER/RIGHT JOIN T1
    ON T1.ref = COALESCE(T2.ref, T3.ref, T4.ref)

获得:

|  T2REF | T2DEPOT |  T3REF | T3DEPOT |  T4REF | T4DEPOT |  T1REF |
|--------|---------|--------|---------|--------|---------|--------|
|      1 |       A |      1 |       A | (null) |  (null) |      1 |
|      1 |       B | (null) |  (null) |      1 |       B |      1 |
| (null) |  (null) |      1 |       C |      1 |       C |      1 |
| (null) |  (null) | (null) |  (null) |      1 |       D |      1 |

为了好玩(并且更好地理解这个请求后者的目的),如果我把T1作为第一个表,我仍然试图让这个工作......

(太糟糕的sqlfiddle似乎没有管理几个具有相同名称的字段......)