SQL - 即使LEFT JOIN失败也返回行

时间:2018-05-14 13:44:05

标签: mysql sql

我有一些查询,其中有几个JOINS从多个表中返回数据

SELECT A.ItemID, A.Title, A.PictureURL as Image, SUM(B.AmountPaid) as revenue, COUNT(*) AS numOrders, B.CheckoutStatus_LastModifiedTime, C.HitCount as today, D.HitCount as yesterday 
    FROM ebay_activelistings A 
    LEFT JOIN ebay_orders B ON 
        A.ItemID = B.ItemID 
        AND ( (B.CheckoutStatus_LastModifiedTime >= :start_date 
        AND B.CheckoutStatus_LastModifiedTime < :end_date) OR B.CheckoutStatus_LastModifiedTime IS NULL) 
        AND (B.CheckoutStatus_Status = 'Complete' OR B.CheckoutStatus_Status IS NULL) 
    LEFT JOIN ebay_hitswatches C ON A.ItemID = C.ItemID 
    LEFT JOIN ebay_hitswatches D ON A.ItemID = D.ItemID 
    WHERE 
        A.ListingStatus = 'Active' 
        AND C.Timstamp LIKE :end_date2 
        AND D.Timstamp LIKE :start_date2
        " . (count($listingIds) > 0 ? 'AND A.ItemID IN ('.implode(',', $listingIds).')' : '') . "
    GROUP BY A.ItemID

此查询正常工作,只会从&#34; ebay_activelistings&#34;中返回一行。表格如果匹配&#34; ItemID&#34;发现在&#34; ebay_orders&#34;表

但是,无论如何,我都希望返回一行,即使没有匹配的&#34; ItemID&#34;在&#34; ebay_orders&#34;那么&#34; B。&#34;数据可以留空,但我仍然可以获得其他数据。

非常感谢任何帮助,谢谢。

3 个答案:

答案 0 :(得分:1)

您已使用LEFT JOIN来保留A中的行,即使他们没有B或C或D中的相应元素。

但是,如果您的WHERE子句中有与B或C或D相关的条件,那么这些行将从您的答案中删除。

将关于B或C或D的条件置于JOIN条件下,将这些条件保留在最终答案中。

简短回答 - 将WHERE条件移入JOIN条件。

SELECT A.ItemID, A.Title, A.PictureURL as Image, SUM(B.AmountPaid) as revenue, COUNT(*) AS numOrders, B.CheckoutStatus_LastModifiedTime, C.HitCount as today, D.HitCount as yesterday 
    FROM ebay_activelistings A 
    LEFT JOIN ebay_orders B ON 
        A.ItemID = B.ItemID 
        AND ( (B.CheckoutStatus_LastModifiedTime >= :start_date 
        AND B.CheckoutStatus_LastModifiedTime < :end_date) OR B.CheckoutStatus_LastModifiedTime IS NULL) 
        AND (B.CheckoutStatus_Status = 'Complete' OR B.CheckoutStatus_Status IS NULL) 
    LEFT JOIN ebay_hitswatches C ON A.ItemID = C.ItemID AND C.Timstamp LIKE :end_date2 
    LEFT JOIN ebay_hitswatches D ON A.ItemID = D.ItemID AND D.Timstamp LIKE :start_date2
    WHERE 
        A.ListingStatus = 'Active' $itemClause
    GROUP BY A.ItemID

但是...在你的php设置$ itemClause如下 - 这将是空白或将包括数字列表。

$itemClause = count($listingIds) > 0 ? ' AND A.ItemID IN ('.implode(',', $listingIds).')' : '';

答案 1 :(得分:0)

我不确定我是否完全了解您的请求的行为以及您对结果的期望。

在您的情况下,这些条件可能过于严格:

AND C.Timstamp LIKE :end_date2 
AND D.Timstamp LIKE :start_date2

也许试试

AND (C.Timstamp IS NULL OR C.Timstamp LIKE :end_date2 )
AND (D.Timstamp IS NULL OR LIKE :start_date2)

答案 2 :(得分:0)

考虑以这种方式工作的外部联接:

如果未找到匹配的行,则生成虚拟行以代替匹配的行。该虚拟行完全由NULL值组成。

当我们到达WHERE子句时,任何需要外连接表中的列为非NULL的条件都将排除生成的虚拟行。这有效地否定了“外在性”#34;连接,使其等效于内连接。

将其与问题中的查询特定相关:WHERE子句中的此条件:

 C.Timstamp LIKE :end_date2 

要求外连接表Timstamp中的C为非NULL。

对于具有C.Timstamp的NULL值的任何行,此条件的计算结果为NULL。由于条件未评估为TRUE,因此将排除该行。这就是我们观察到的行为的原因。

修复方法是删除C.Timstamp非NULL的要求。

通常的模式是从WHERE子句中删除条件,并重新定位到连接的ON子句,例如。

   LEFT
   JOIN ebay_hitswatches C
     ON C.ItemID = A.ItemID
    AND C.Timstamp LIKE :end_date2
  WHERE ...