【问题标题】:Cross join behavior交叉连接行为
【发布时间】:2013-07-11 07:39:52
【问题描述】:

我有一个基于位置跟踪零售销售的数据库。我有一个带有 ID 和各种其他位置特定信息的位置表,一个带有 itemID 和所有其他项目信息的零售项目表,以及一个包含位置和项目 ID 以及其他信息的零售使用表销售(数量、销售价格等)。我正在尝试进行查询,该查询将返回所有零售商品以及在给定日期范围内按位置分组的每个商品的销售量总和。

我发现了this SO 问题,并在一定程度上模仿了 Tony Andrews 的回答,但它的行为与我预期的不同。

如果我不包括日期范围,我可以获得完整的商品列表(所有 29 件商品都按预期重新调整)和销售数量:

SELECT i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, AVG(u.Price) AS Price, SUM(u.Quantity) AS Quantity, l.Description, l.LocationID, i.Description AS ItemDescription 
FROM Location as l CROSS JOIN RetailSaleItems as i
  INNER JOIN RetailSaleUsage as u ON l.LocationID = i.LocationID AND i.ItemNo = u.ItemNo
WHERE (l.LocationID IN(1)) AND (i.Inactive = 0)
GROUP BY i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, l.[Description], l.LocationID, i.[Description]
ORDER BY l.[Description]

当我尝试限制日期范围时,比如到今年 1 月,我会丢失 5 条记录,并且尽我所能告诉它,因为它们没有在指定的日期范围内显示在 RetailSaleusage 表中。但这没有任何意义,因为还有 15 项其他项目也没有出现在该日期范围内,但它们出现在结果中。

我使用的日期范围的 SQL 是:

SELECT i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, AVG(u.Price) AS Price, SUM(u.Quantity) AS Quantity, l.Description, l.LocationID, i.Description AS ItemDescription 
FROM Location as l CROSS JOIN RetailSaleItems as i
  INNER JOIN RetailSaleUsage as u ON l.LocationID = i.LocationID AND i.ItemNo = u.ItemNo
WHERE (l.LocationID IN(1)) 
  AND (i.Inactive = 0) AND (u.[Date] >= '1/1/2013' AND u.[Date] <= '1/31/2013')
GROUP BY i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, l.[Description], l.LocationID, i.[Description]
ORDER BY l.[Description]

我在 MSDN 上找到了 this 文章,该文章讨论了交叉联接在包含 where 子句时的作用类似于内部联接,但其中一个 cmets 指出仅当 where 规定联接标准时才适用。由于我的 SQL 的 where 只是限制了日期范围,我认为这不是问题。

对此的任何指导将不胜感激。

【问题讨论】:

    标签: sql


    【解决方案1】:

    您可能不需要CROSS JOIN。它们在实践中并没有太多使用(很少,它们非常有用,但很少)。

    无论如何,您可能想对[LEFT|RIGHT] [OUTER] JOINs 进行一些研究(OUTER 关键字是可选的)。对于INNER JOINs,记录必须存在于每个连接的表中。对于OUTER JOINs,一条记录必须至少存在一个表中才能返回数据。哪个表取决于您执行的是LEFT JOIN 还是RIGHT JOIN

    我已经尝试在下面编写正确的查询 - 但我不知道您的数据模型并做了一些“直觉猜测”。试试看,看看你能想出什么。

    SELECT i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, AVG(u.Price) AS Price, SUM(u.Quantity) AS Quantity, l.Description, l.LocationID, i.Description AS ItemDescription 
    FROM Location as l 
        INNER JOIN RetailSaleItems as i ON i.LocationID = l.LocationID
        LEFT JOIN RetailSaleUsage as u ON l.LocationID = u.LocationID
    WHERE (l.LocationID IN(1)) AND (i.Inactive = 0) AND (i.ItemNo = u.ItemNo OR u.ItemNo IS NULL)
    GROUP BY i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, l.[Description], l.LocationID, i.[Description]
    ORDER BY l.[Description]
    

    更新:为了帮助您根据下面的评论回答您的问题,您需要更改按日期范围限制的位置。目前,您将所有结果限制在RetailSaleUsage 表中的指定日期范围内,因为条件放在WHERE 子句中。相反,我们需要在连接RetailSaleUsage 表时将限制指定为JOIN 的条件。看看下面的查询。那应该为你做。

    SELECT i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, AVG(u.Price) AS Price, SUM(u.Quantity) AS Quantity, l.Description, l.LocationID, i.Description AS ItemDescription 
    FROM Location as l 
        INNER JOIN RetailSaleItems as i ON i.LocationID = l.LocationID
        LEFT JOIN RetailSaleUsage as u ON l.LocationID = u.LocationID AND u.[Date] BETWEEN '1/1/2013' AND '1/31/2013'
    WHERE (l.LocationID IN(1)) AND (i.Inactive = 0) AND (i.ItemNo = u.ItemNo OR u.ItemNo IS NULL)
    GROUP BY i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, l.[Description], l.LocationID, i.[Description]
    ORDER BY l.[Description]
    

    HTH。

    【讨论】:

    • 我最初尝试过这样的事情,但它只返回在日期范围内有活动的项目,而不是所有项目。
    • 啊,我明白你在说什么。查看您的查询,您在 WHERE 子句中限制了日期范围。这限制了整个查询的结果。相反,您需要将联接中的日期范围限制为 RetailSaleUsage 作为附加的 JOIN 条件。我会修改我上面的答案给你看。
    • 很高兴我能帮上忙。 :)
    猜你喜欢
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 2010-10-17
    • 2012-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多