4

这是我一直遇到的 SQL 问题!(我使用 Sql-Server/sql-management studio)我想离开加入一个表,但前提是它通过了需要另一个加入的测试。所以我将 B 加入 A 但我只想加入 B 如果 B 加入表 C 通过测试...

SELECT A.* 
FROM TableA A
LEFT JOIN TableB B on A.BID = B.BID  --only want to join B if C passes the test
LEFT JOIN TableC C on B.CID = C.CID
WHERE C.PassesTest -- not correct: throws out records from A that don't pass test

因此,如果 C 通过测试,我只想离开加入 B。正如我的标题,我基本上想左连接 2 个内部连接的表......“C.PassesTest 上的左连接(b 内连接 c)”基本上是我想要做的。

我的 2 个直接想法都失败了:
1. 如果您将 PassesTest 加入到 C 中,(... left join c on B.CID = C.CID AND C.PassesTest ...)您仍然拥有所有 B 记录在你不想要的地方闲逛。
2. 如果您将测试放在 where(如上),它会抛出所有未通过但我想要的 A 记录(因为它是左连接)。

我可以想到 2 个解决方案,但它们都有点痛苦......真的没有更简单的方法吗?

  1. 加入所有 B/C - 这在逻辑上是我想要的,但显然不是最佳的,因为它在加入之前从 B 和 C 中获取所有内容(所以它很慢)

    SELECT A.* 
    FROM TableA A
    LEFT JOIN (
      SELECT * 
      FROM TableB B 
      INNER JOIN TableC C ON B.CID = C.CID 
      WHERE C.PassesTest
    ) BC ON BC.BID = A.BID
    
  2. 做某种嵌套选择。下面的方式好像有点多余……或许可以写得好一点

    SELECT ABC.StuffFromA FROM (
      SELECT * 
      FROM TableA A
      LEFT JOIN TableB B on A.BID = B.BID
      LEFT JOIN TableC C ON B.CID = C.CID 
    ) ABC
    LEFT JOIN TableB B on ABC.BID = B.BID AND ABC.PassesTest 
    

无论如何,这是我一直遇到的事情,我总是发现自己不得不做一些非常困难的事情才能让它发挥作用!似乎应该有一个更简单的解决方案......或者这只是一个看似困难的 SQL 问题?

4

1 回答 1

2

version 1不需要是子查询,您只需要()围绕该INNER JOIN部分...

SELECT
  A.* 
FROM
  TableA A
LEFT JOIN
  (
    TableB B 
  INNER JOIN
    TableC C
      ON  B.CID = C.CID 
      AND C.PassesTest
  )
    ON B.BID = A.BID

我还将您所拥有的内容作为谓词WHERE中的子句INNER JOIN


另外,请注意,在您的子查询版本和此示例中,整个 TableB 是否必须在加入 TableA之前加入 TableC。

SQL 被编译成一个执行计划,优化器有很多选项来防止这种情况发生。仅仅因为你这样写并不意味着 RDBMS 会盲目地遵循它而不进行优化。

于 2013-07-11T21:05:56.153 回答