直接与第一个表或通过中介加入第三个表

时间:2015-11-20 12:17:12

标签: sql-server tsql sql-server-2008-r2 left-join

我正在尝试加入3个表,其中第三个表包含对第二个表和第一个表的引用;我想要这些引用中的任何一个的结果。但是,在第三个表引用第一个表的情况下,我不需要第二个表的结果。

这很难解释,所以我用下面的例子说明了我的意思。

第一个select语句产生6行;我理解为什么,但那不是我追求的目标。

第二个2给出了我追求的结果,但是它们有一个代码味道。任何人都可以建议更好的方法来实现相同的输出吗?

另请参阅SQL小提琴:http://sqlfiddle.com/#!3/8029cc/1

--code to setup my example

    declare @t1 table (id bigint, val nvarchar(10))
    declare @t2 table (id bigint, t1Id bigint, val2 nvarchar(10))
    declare @t3 table (id bigint, t1Id bigint, t2Id bigint, val3 nvarchar(10))

    insert @t1 (id, val) values (1, '1.1')

    insert @t2 (id, t1Id, val2) 
    values (1, 1, '2.1')
    ,(2, 1, '2.2')
    ,(3, 1, '2.3')

    insert @t3 (id, t1Id, t2Id, val3) 
    values (1, 1, null, 'XXX')
    , (1, null, 1, '3.1')
    ,(2, null, 2, '3.2')
    ,(3, null, 3, '3.3')

--this produces 6 results; I only want 4

    select *
    from @t1 t1
    left outer join @t2 t2 
        on t2.t1Id = t1.Id
    left outer join @t3 t3
        on t3.t2Id = t2.Id
        or t3.t1Id = t1.id

--this works, but means repeating myself; which I'd prefer not to do if possible (could use a cte to make that simpler in the real world scenario, but still not ideal)

    select t1.id, t2.id, t3.id, t1.val, t2.val2, t3.val3
    from @t1 t1
    left outer join @t2 t2 
        on t2.t1Id = t1.Id
    left outer join @t3 t3
        on t3.t2Id = t2.Id

    union all

    select t1.id, null, t3.id, t1.val, null, t3.val3
    from @t1 t1
    left outer join @t3 t3
        on t3.t1Id = t1.id

--this works too, but feels very hacky

    select t1.id, t2.id, t3.id, t1.val, t2.val2, t3.val3
    from @t1 t1
    left outer join 
    (
        select id, t1id, val2
        from @t2

        union all

        select null, null, null

    ) t2 
        on coalesce(t2.t1Id,t1.Id) = t1.Id
    left outer join @t3 t3
        on t3.t2Id = t2.Id
        or (t3.t1Id = t1.id and t2.Id is null)

更新

我只是想到了另一个比上面那些感觉更清洁的解决方案;虽然我对它有点不舒服......

--another option; again slightly hacky

    select id, id2, id3, val, val2, val3
    from
    (
        select t1.id
        , case when t3.t1Id = t1.id then null else t2.id end id2
        , t3.id id3
        , t1.val
        , case when t3.t1Id = t1.id then null else t2.val2 end val2
        , t3.val3
        , row_number() over (partition by t1.id order by case when t3.t1Id = t1.id then null else t2.id end, t3.id) x
        from @t1 t1
        left outer join @t2 t2 
            on t2.t1Id = t1.Id
        left outer join @t3 t3
            on t3.t2Id = t2.Id
            or t3.t1Id = t1.id
    ) t
    where id2 is not null or x = 1

3 个答案:

答案 0 :(得分:1)

也许我没有完全理解你的要求/输出。

但是,查询应该具有相同的结果

SELECT *
FROM t3 
LEFT JOIN t2 
  ON t2.id = t3.t2Id
LEFT JOIN t1
  ON t3.t1Id = t1.id
  AND t2.id IS NULL

答案 1 :(得分:1)

尝试此查询,它将产生与上一个查询相同的输出结果:

SELECT T.ID, 
       CASE WHEN T3.t2Id IS NULL THEN NULL ELSE  T.T2ID END AS T2ID,
       T3.id AS T3ID,
       T.VAL, 
       CASE WHEN T3.t2Id IS NULL THEN NULL ELSE  T.VAL2 END AS VAL2,
       T3.VAL3
FROM (SELECT T1.id, 
             T1.val,
             T2.Id AS T2ID, 
             T2.val2
      FROM @t1 AS T1 JOIN @t2 AS T2 
                  ON T1.id = T2.t1id
      ) AS T JOIN @t3 AS T3 
           ON T.T2ID = T3.ID
ORDER BY  T3.VAL3

<强> test is here

输出结果

enter image description here

答案 2 :(得分:1)

非常简单 - 你的错误是你的起点。 从表3开始,然后连接到其他人 - 然后添加where条件。 即。

    SELECT * FROM  @t3
    LEFT OUTER JOIN @t1
    ON [@t1].id = [@t3].t1id
    LEFT OUTER JOIN @t2
    ON [@t2].id = [@t3].t2id
    WHERE [@t1].id IS NOT NULL
    OR ( [@t2].id IS NOT NULL AND [@t1].id IS NULL)