【问题标题】:LEFT OUTER JOIN with a WHERE clause带有 WHERE 子句的 LEFT OUTER JOIN
【发布时间】:2011-01-30 20:33:50
【问题描述】:

我有两张桌子。 indRailType 包含与我在其他表中用于指示轨道类型的 ID 值配对的名称列表。 WO_BreakerRail 包含一个日期列和一个铁路代码列,对应于indRailType 和其他一些数据中的相同代码。 WO_BreakerRail 中有一行,表示每个轨道类型上的任何活动,每个日期。所以我可以有 3 行日期为 3/19/2010,每行表示不同的铁路代码,以及发生了什么。

当我使用下面的LEFT OUTER JOIN 时,我得到一个包含所有类型铁路的表格,在 19 日没有发生任何事情的行中有空值。现在,这只是工作,因为我现在在我的WO_BreakerRail 表中只有一个日期,即 19 日。当我添加更多具有不同日期的行时,事情就会变得混乱。

这是我的 SQL 语句,它现在给出了我想要的结果:

SELECT WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, 
    WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, 
    WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop
FROM indRailType
LEFT OUTER JOIN WO_BreakerRail 
    ON indRailType.RailCode = WO_BreakerRail.RailCode

现在,当我添加 WHERE WO_BreakerRail.Date = @Date 子句时,我丢失了 JOIN 中的所有行,但什么也没发生。我不想要那个。从阅读开始,听起来像 FULL OUTER JOIN 是我想要的,但 SQL Server Compact Edition 不支持 FULL OUTER JOINs。有没有办法解决这个问题,还是我完全在寻找其他东西?

【问题讨论】:

    标签: sql-server join sql-server-ce


    【解决方案1】:

    试试:

    SELECT WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, 
        WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged,
        WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop
    FROM indRailType
    LEFT OUTER JOIN WO_BreakerRail ON indRailType.RailCode = WO_BreakerRail.RailCode 
                AND WO_BreakerRail.Date = @Date
    

    因此将AND WO_BreakerRail.Date = @Date 添加到连接中

    【讨论】:

    • 不要忘记考虑@Date 的“时间”部分。如果值可以在午夜和午夜之间变化,则必须使用某种形式的 between 子句。
    • 这个答案效果很好,谢谢。菲利普:感谢您的指点,虽然我在这个项目的早期遇到了这个问题,这让我很困惑,但我最终在我的 C# 代码中修复了它,删除了所有时间部分,将每个日期默认为午夜。
    • @Wesley,最好是“地板”日期时间数据类型来删除时间,所以时间是 00:00:00.000 而不是午夜。
    • 是的——我建议在数据库中这样做,以防其他应用程序传入“不干净”的数据。
    【解决方案2】:

    谓词条件需要在连接的On 子句中,而不是在where 子句中。外部联接的工作方式是在分析联接条件之后,将所有与内部不匹配的“外部”行添加回......但这一切都发生在处理 where 子句之前。因此,如果 where 子句谓词从外连接的外侧过滤属性,则所有这些行将再次被删除......(它们都是空的)。将谓词放在连接条件中,然后在将丢失的行添加回之前对其进行评估...

    SELECT b.ID, t.RailType, b.CreatedPieces, 
           b.OutsideSource, b.Charged, b.Rejected, 
           b.RejectedToCrop 
    FROM indRailType t
       LEFT JOIN WO_BreakerRail b
            ON t.RailCode = b.RailCode 
                And b.Date = @Date
    

    【讨论】:

      【解决方案3】:

      你可以使用这个 where 子句:

      WHERE WO_BreakerRail.Date = @Date OR WO_BreakerRail.Date IS NULL
      

      【讨论】:

      • 使用外连接时,最好在 ON 子句中考虑任何“isnull 工作”,而不是 where 子句
      【解决方案4】:

      LEFT OUTER JOIN 语句中添加WO_BreakerRail.Date = @Date 而不是WHERE

      SELECT
          WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop
          FROM indRailType 
              LEFT OUTER JOIN WO_BreakerRail ON indRailType.RailCode = WO_BreakerRail.RailCode AND WO_BreakerRail.Date = @Date
      

      或者您可以将其添加到 WHERE:

      SELECT
          WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop
          FROM indRailType 
              LEFT OUTER JOIN WO_BreakerRail ON indRailType.RailCode = WO_BreakerRail.RailCode
          WHERE (WO_BreakerRail.Date = @Date OR WO_BreakerRail.Date IS NULL)
      

      【讨论】:

        【解决方案5】:

        您想要的是将您的WO_BreakerRail 过滤到所需的日期之前 LEFT JOINing 它到indRailType。如果您只是添加 WHERE 语句,则相反,这会导致您描述的问题。

        到目前为止提供的解决方案应该可以工作(将条件移动到 LEFT JOIN),但我想提出一个替代方案:您可以使用子查询来指定应该完成的事情的顺序:

        SELECT R.ID, indRailType.RailType, R.CreatedPieces, R.OutsideSource, R.Charged, R.Rejected, R.RejectedToCrop
          FROM indRailType LEFT OUTER JOIN
               (SELECT * FROM WO_BreakerRail WHERE Date = @Date) R
               ON indRailType.RailCode = R.RailCode
        

        (未经测试,但据我所知,SQL Server CE 支持子查询。)

        【讨论】:

          【解决方案6】:

          或者您可以将其添加到WHERE:

          SELECT WO_BreakerRail.ID, indRailType.RailType, 
            WO_BreakerRail.CreatedPieces, 
            WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, 
            WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop 
          FROM indRailType, WO_BreakerRailCode 
          WHERE indRailType.RailCode = WO_BreakerRail.RailCode(+) 
           AND WO_BreakerRail.Date (+) =@Date 
          

          【讨论】:

          • (+) 是 Oracle 连接运算符,OP 使用 SQL-Server。此外,不建议使用该外连接语法,因为它比标准 Left Join 语法更受限制且更难阅读。 Oracle Docs: Joins
          • 这在 Oracle 中也不起作用。它只会使用该过滤器提取外部连接的表行。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-05-22
          • 2011-04-26
          • 2010-11-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-21
          相关资源
          最近更新 更多