LEFT JOIN 多个子查询

LEFT JOIN multiple sub queries

我的目的是创建一个 table,其中包含每种产品在两个不同年份的订单数量和收入。 我的想法是使用双左连接,但我不明白为什么这个查询在 MS ACCESS 上不起作用。 我决定使用 LEFT JOIN,因为在每年的子查询中,如果未订购某些产品,则可能不会出现。 子查询 a 和 b 都可以。他们分开工作。 这个查询有什么问题?

SELECT p.PK_Product_ID, a.[2013_Orders], a.[2013_Gross_Value], b.[2014_Orders], b.[2014_Gross_Value]
    FROM Products AS p

LEFT JOIN 
     (SELECT p.PK_Product_ID AS Product_ID, COUNT(o.PK_Order_ID) AS 2013_Orders,  
     SUM((p.UnitPrice*od.Quantity)) AS 2013_Gross_Value
     FROM [Order Details] AS od, p, Orders AS o
     WHERE od.FK_Product_ID = p.PK_Product_ID
     AND od.FK_Order_ID = o.PK_Order_ID
     AND YEAR(o.OrderDate) = 2013
     GROUP BY p.PK_Product_ID) AS a

ON p.PK_Product_ID = a.Product_ID

LEFT JOIN 
    (SELECT p.PK_Product_ID AS Product_ID, COUNT(o.PK_Order_ID) AS 2014_Orders,  SUM((p.UnitPrice*od.Quantity)) AS 2014_Gross_Value
    FROM od, p, o
    WHERE od.FK_Product_ID = p.PK_Product_ID
    AND od.FK_Order_ID = o.PK_Order_ID
    AND YEAR(o.OrderDate) = 2014
    GROUP BY p.PK_Product_ID) AS b
 ON p.PK_Product_ID = b.Product_ID;

这个查询没有意义。你说 sub-queries 运行 很好——但他们没有办法。尝试 运行 执行此查询

 SELECT p.PK_Product_ID AS Product_ID, COUNT(o.PK_Order_ID) AS 2013_Orders,  
 SUM((p.UnitPrice*od.Quantity)) AS 2013_Gross_Value
 FROM [Order Details] AS od, p, Orders AS o
 WHERE od.FK_Product_ID = p.PK_Product_ID
 AND od.FK_Order_ID = o.PK_Order_ID
 AND YEAR(o.OrderDate) = 2013
 GROUP BY p.PK_Product_ID

我希望它给出一个错误,即“p”不是 table 的名称。

也许你是这个意思?

 SELECT p.PK_Product_ID AS Product_ID, COUNT(o.PK_Order_ID) AS 2013_Orders,  
 SUM((p.UnitPrice*od.Quantity)) AS 2013_Gross_Value
 FROM [Order Details] AS od, Products as p, Orders AS o
 WHERE od.FK_Product_ID = p.PK_Product_ID
 AND od.FK_Order_ID = o.PK_Order_ID
 AND YEAR(o.OrderDate) = 2013
 GROUP BY p.PK_Product_ID

这意味着您可能想要这样的东西:

SELECT p.PK_Product_ID, a.[2013_Orders], a.[2013_Gross_Value], b.[2014_Orders], b.[2014_Gross_Value]
    FROM Products AS p

LEFT JOIN (
   SELECT p.PK_Product_ID AS Product_ID, COUNT(o.PK_Order_ID) AS 2013_Orders, SUM((p.UnitPrice*od.Quantity)) AS 2013_Gross_Value
   FROM [Order Details] AS od
   JOIN Products as p ON od.FK_Product_ID = p.PK_Product_ID 
   JOIN Orders AS o ON od.FK_Order_ID = o.PK_Order_ID AND YEAR(o.OrderDate) = 2013
   GROUP BY p.PK_Product_ID         
) AS a ON p.PK_Product_ID = a.Product_ID

LEFT JOIN (
   SELECT p.PK_Product_ID AS Product_ID, COUNT(o.PK_Order_ID) AS 2013_Orders, SUM((p.UnitPrice*od.Quantity)) AS 2013_Gross_Value
   FROM [Order Details] AS od
   JOIN Products as p ON od.FK_Product_ID = p.PK_Product_ID 
   JOIN Orders AS o ON od.FK_Order_ID = o.PK_Order_ID AND YEAR(o.OrderDate) = 2013
   GROUP BY p.PK_Product_ID         
) AS b ON p.PK_Product_ID = b.Product_ID;

但是,我不会为两个 sub-queries 或什至 1 个 sub-query 而烦恼 - 它只会减慢你的速度 - 这样做:

SELECT p.PK_Product_ID, 
  SUM(CASE WHEN COALESCE(o.OrderYear,0) == 2013 THEN 1 ELSE 0 END) as 2013_Orders,
  SUM(CASE WHEN COALESCE(o.OrderYear,0) == 2013 THEN OrderValue ELSE 0 END) as 2013_Gross_Value,

  SUM(CASE WHEN COALESCE(o.OrderYear,0) == 2014 THEN 1 ELSE 0 END) as 2014_Orders,
  SUM(CASE WHEN COALESCE(o.OrderYear,0) == 2014 THEN OrderValue ELSE 0 END) as 2014_Gross_Value,
FROM Products AS p
LEFT JOIN [Order Details] AS od ON od.FK_Product_ID = p.PK_Product_ID 
LEFT JOIN Orders AS o ON od.FK_Order_ID = o.PK_Order_ID
WHERE YEAR(o.OrderDate) in (2013, 2014) -- this is not needed but will may make it faster
GROUP BY p.PK_Product_ID

记住,在 SQL 中你应该分组思考——第一组是订单……年份晚些。

您可以使用条件聚合来完成:

SELECT p.PK_Product_ID AS Product_ID,
       SUM(IIF(YEAR(o.OrderDate) = 2013, 1, 0)) AS 2013_Orders,
       SUM(IIF(YEAR(o.OrderDate) = 2013, p.UnitPrice * od.Quantity, 0)) AS 2013_Gross_Value,
       SUM(IIF(YEAR(o.OrderDate) = 2014, 1, 0)) AS 2014_Orders,
       SUM(IIF(YEAR(o.OrderDate) = 2014, p.UnitPrice * od.Quantity, 0)) AS 2014_Gross_Value
FROM (Products AS p LEFT JOIN [Order Details] AS od ON od.FK_Product_ID = p.PK_Product_ID)
LEFT JOIN (SELECT * FROM Orders WHERE YEAR(OrderDate) IN (2013, 2014)) AS o ON od.FK_Order_ID = o.PK_Order_ID
GROUP BY p.PK_Product_ID

如果您只想要 2013 and/or 2014 年订购的产品,那么您可以将 LEFT 连接更改为 INNER 连接。

你为什么不 运行 通过单个查询手动 cross-tab 样式。我查询的订单 table 仅适用于 2013 年 1 月 1 日至 2015 年 1 月 1 日之前的日期范围内的记录。这为我提供了 2 年内的所有订单,无论商品是否在一年内开始销售或者另一个。

现在,我正在做一个基于 IIF() 的 sum()。如果订单的年份是 2013 年,则它们的总数分别应用 1 或 0。 2014 年也是如此。根据构造和最终列名称,这些应该是显而易见的。如果记录不适用于当年,则为零。总价值相同,我只是根据适用情况乘以 1 或 0。

唯一没有意义的是从产品中获取单价table。实际上,我本以为订单详细信息级别会有价格,因为这些年来价格明显波动,我认为 2013 年和 2014 年的价格分别与当前 2020 年费率数据库中的价格无关。所以,这可能需要适当调整。

SELECT 
        od.FK_Product_ID,
        sum( iif( year( o.orderDate ) = 2013, 1, 0 )) Orders_2013,
        sum( iif( year( o.orderDate ) = 2014, 1, 0 )) Orders_2014,
        sum( iif( year( o.orderDate ) = 2013, 1, 0 ) * p.UnitPrice * od.Quantity ) GrossValue_2013,
        sum( iif( year( o.orderDate ) = 2014, 1, 0 ) * p.UnitPrice * od.Quantity ) GrossValue_2014
    FROM 
        Orders AS o
            JOIN [Order Details] AS od
                ON o.PK_Order_ID = od.FK_Order_ID
                JOIN [Products] as p
                    on od.FK_Product_ID = p.PK_Product_ID
    WHERE 
            o.OrderDate >= #1/1/2013#
        AND o.OrderDate < #1/1/2015#
    GROUP BY 
        od.FK_Product_ID