【问题标题】:LEFT JOIN with conditions带条件的 LEFT JOIN
【发布时间】:2012-08-22 13:57:57
【问题描述】:

我正在使用 MS SQL。我有两张桌子:

1) “OrderProducts” - 此表存储订单拥有的所有产品。还有另一个 Orders 主表,我们可以从这张图中省略。 Orders 主表存储订单的主要数据,而 OrderProducts 表存储详细信息。

2) “TransactionFeeProducts” - 此表存储我要为订单收取的所有产品交易费用。它有一个 BatchID,其中多个产品可以有相同的 BatchID。

基本上,OrderDate 介于 TransactionFeeProducts.FromDate 和 TransactionFeeProducts.ToDate 之间的所有订购产品,都将收取 TransactionFeeProducts.TransactionFee

订购产品

  • 产品ID
  • 数量
  • 订购日期

TransactionFeeProducts

  • 批次ID
  • 产品ID
  • 从日期
  • 至今
  • 交易费用

SQL:

SELECT SUM(Quantity) as Orders, 
TransactionFeeProducts.ProductID, FromDate, ToDate 
FROM TransactionFeeProducts 
LEFT JOIN OrderProducts ON TransactionFeeProducts.ProductID = OrderProducts.ProductID
WHERE
OrderDate >= TransactionFeeProducts.FromDate AND 
OrderDate <= TransactionFeeProducts.ToDate AND 
TransactionFeeProducts.BatchID = 3
GROUP BY TransactionFeeProducts.ProductID, FromDate, ToDate 
ORDER BY SUM(Quantity) DESC

我希望 SQL 返回 TransactionFeeProducts 中 BatchID = 3 的所有记录。 SUM(Quantity) 应该只给我在 TransactionFeeProducts.FromDate 和 TransactionFeeProducts.ToDate 之间进行 OrderDate 的总和

如果 SUM(Quantity) 为 0,则该字段应为 NULL 或 0。

我现在的问题是,如果 SUM(Quantity) 为 0,SQL 不会返回任何记录。

请帮忙。非常感谢。

【问题讨论】:

    标签: sql sql-server-2008 inner-join


    【解决方案1】:

    将 JOIN 条件更改为类似

    SELECT  SUM(Quantity) as Orders,  
            TransactionFeeProducts.ProductID, 
            FromDate, 
            ToDate  
    FROM    TransactionFeeProducts LEFT JOIN 
            OrderProducts   ON  TransactionFeeProducts.ProductID = OrderProducts.ProductID 
                            AND OrderDate >= TransactionFeeProducts.FromDate 
                            AND OrderDate <= TransactionFeeProducts.ToDate 
    WHERE   TransactionFeeProducts.BatchID = 3 
    GROUP BY    TransactionFeeProducts.ProductID, 
                FromDate, 
                ToDate  
    ORDER BY    SUM(Quantity) DESC
    

    不同之处在于,如果您将过滤条件放在WHERE 子句中,它将影响查询过滤,就像您使用INNER JOIN 一样,说明您将只包含来自TransactionFeeProducts 的条目,其中OrderDate &gt;= TransactionFeeProducts.FromDate and OrderDate &lt;= TransactionFeeProducts.ToDate

    看看下面的例子

    DECLARE @TABLE1 TABLE(
            ID INT,
            FromDate DATETIME,
            ToDate DATETIME
    )
    
    INSERT INTO @TABLE1 SELECT 1, '01 Jan 2012','31 Jan 2012'
    
    DECLARE @TABLE2 TABLE(
            ID INT,
            DateValue DATETIME
    )
    
    INSERT INTO @TABLE2 SELECT 1, '01 Feb 2012'
    
    SELECT  *
    FROM    @TABLE1 t1 LEFT JOIN
            @TABLE2 t2  ON  t1.ID = t2.ID
                        AND t2.DateValue BETWEEN t1.FromDate AND t1.ToDate
    
    SELECT  *
    FROM    @TABLE1 t1 LEFT JOIN
            @TABLE2 t2 ON   t1.ID = t2.ID
    WHERE   t2.DateValue BETWEEN t1.FromDate AND t1.ToDate
    

    选择 1 说:

    返回 T1 中的所有行,仅返回 T2 中 t1.ID = t2.ID AND t2.DateValue BETWEEN t1.FromDate AND t1.ToDate 的行

    另一方面,选择 2 表示:

    仅返回 T1 中的所有行,仅返回 T2 中 t1.ID = t2.ID 的行,然后仅返回 t2.DateValue BETWEEN t1.FromDate AND t1.ToDate 中的行

    SQL SERVER – Introduction to JOINs – Basic of JOINs 总是很方便。

    【讨论】:

    • 很好,但作为旁白 Aaron Bertrand makes a good case for not using between 这让我很伤心,因为我喜欢它
    • 很好的解释,为提供示例和解释而点赞和支持
    • 很好的例子!如果我理解正确,select 1 将返回我们插入到表 t1 中的一条记录,其中 null 用于表 t2 中的字段。另一方面,select 2 根本不会返回任何记录!
    【解决方案2】:

    我更喜欢 astander 的方法(在 JOIN 中过滤),但有时有用的替代方法是在连接字段上简单地添加 OR IS NULL,例如

    WHERE
     TransactionFeeProducts.BatchID = 3
     AND
    (OrderProducts.ProductID IS NULL
     OR 
    (
       OrderDate >= TransactionFeeProducts.FromDate AND 
       OrderDate <= TransactionFeeProducts.ToDate 
    
    ))
    

    【讨论】:

      猜你喜欢
      • 2014-11-24
      • 2016-01-11
      • 2014-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多