有没有办法让这个查询与JOIN一起使用,还是我必须使用UNION?

时间:2016-08-12 01:02:28

标签: sql sql-server

我可能正在尝试将JOIN用于此处不打算使用的目的。

这是我的(简化)表格结构:

表A

  • ID
  • 表C ID
  • IsStatic(位)

表B

  • ID
  • 表A ID(可空)
  • 表C ID

表C

  • ID

我的目标是将所有表B行连接到表A的行,其中表B的表A ID列具有值并且等于表A的ID列值。

我还需要表B的表A ID列没有值的所有表B行。

我还需要表A的所有行,没有连接的表B行,表A的IsStatic列是真的。

表C还必须与表A或表B相关联。如果表B没有TableAID的值,那么TableCID的值应该等于TableC的ID值。否则TableA的TableCID应该等于TableC的ID值。

这是一些用于创建一些TABLE变量并填充样本数据的SQL:

DECLARE @TableA TABLE (TableAID int, TableCID int, IsStatic bit)
DECLARE @TableB TABLE (TableBID int, TableAID int, TableCID int)
DECLARE @TableC TABLE (TableCID int)

INSERT INTO @TableC (TableCID) VALUES (1)
INSERT INTO @TableC (TableCID) VALUES (2)

INSERT INTO @TableA (TableAID, TableCID, IsStatic) VALUES (1, 1, 0)
INSERT INTO @TableA (TableAID, TableCID, IsStatic) VALUES (2, 2, 1)
INSERT INTO @TableA (TableAID, TableCID, IsStatic) VALUES (3, 2, 1)
INSERT INTO @TableA (TableAID, TableCID, IsStatic) VALUES (4, 2, 0)

INSERT INTO @TableB (TableBID, TableAID, TableCID) VALUES (1, NULL, 1)
INSERT INTO @TableB (TableBID, TableAID, TableCID) VALUES (2, 1, 1)
INSERT INTO @TableB (TableBID, TableAID, TableCID) VALUES (3, 2, 2)

这是我的(简化)查询,它不起作用:

SELECT
    a.TableAID,
    b.TableBID
FROM @TableC c
LEFT OUTER JOIN @TableB b ON
    (b.TableAID IS NOT NULL OR (b.TableAID IS NULL AND b.TableCID = c.TableCID))
LEFT OUTER JOIN @TableA a ON
    a.TableCID = c.TableCID
    AND ((a.IsStatic = 1 AND b.TableBID IS NULL)
        OR (b.TableBID IS NOT NULL AND b.TableAID = a.TableAID))

使用sampel数据的查询结果是:

TableAID TableBID
-----------------
NULL     1
1        2
NULL     3       (not required)
NULL     2       (not required)
2        3

所需的结果是:

TableAID TableBID
-----------------
NULL     1
3        NULL     (missing)
2        3
1        2

此查询的问题在于,如果TableB.TableAID没有值,则从不包括TableA.IsStatic为真而没有任何匹配的TableB行的表A行。还包括一些TableB行,它们不应该是。

我能看到的唯一另一种方法是使用union not exists,但我希望以更有效的方式执行此操作。

更新:添加WHERE子句会删除“不需要”的行,但仍会省略缺失的行。

WHERE (b.TableBID IS NULL OR b.TableAID IS NULL OR b.TableAID = a.TableAID)

与where子句相同查询的结果是:

TableAID TableBID
-----------------
NULL     1
1        2
2        3

2 个答案:

答案 0 :(得分:4)

select b.TableAID, b.TableBID
from @TableB b
    left join @TableA a on a.TableAID = b.TableAID
    inner join @TableC c on c.TableCID = case when a.TableAID IS NULL then b.TableCID else a.TableCID end

union all

select a.TableAID, NULL
from @TableA a
    inner join @TableC c on c.TableCID = a.TableCID
    left join @TableB b on b.TableAID = a.TableAID
where b.TableAID is NULL
    and a.IsStatic = 1

答案 1 :(得分:2)

多么令人头疼的事。我认为这是表达它的另一种方式。你必须看看表现是否良好:

select a.TableAID, b.TableBID
  from (select a.*
          from @TableA a
          join @TableC c
            on c.TableCID = a.TableCID) a
  full outer join (select b.*
                     from @TableB b
                     join @TableC c
                       on c.TableCID = b.TableCID) b
    on b.TableAID = a.TableAID
 where b.TableBID is not null or a.IsStatic = 1

我还应该提到,使用您提供的示例数据确定上述查询是否真的符合您的要求很难确定。为了说明,如果我在下面使用这个简单忽略@TableC表的简化查询,我仍然可以获得样本数据的正确结果:

 select a.TableAID, b.TableBID
  from @TableA a
  full outer join @TableB b
    on b.TableAID = a.TableAID
 where b.TableBID is not null or a.IsStatic = 1

编辑:关于OP'的解释的评论中有趣的讨论。要求......但如果我必须解决安东的问题:

select a.TableAID, b.TableBID
  from (select a.*, 
               case when c.TableCID is not null then 1 end as has_c
          from @TableA a
          left join @TableC c
            on c.TableCID = a.TableCID) a
  full outer join (select b.*,
                          case when c.TableCID is not null then 1 end as has_c
                     from @TableB b
                     left join @TableC c
                       on c.TableCID = b.TableCID) b
    on b.TableAID = a.TableAID
 where (b.TableBID is not null or a.IsStatic = 1)
   and (a.has_c = 1 or b.has_c = 1)