【问题标题】:LEFT JOIN multiple sub queriesLEFT JOIN 多个子查询
【发布时间】:2021-01-28 02:41:17
【问题描述】:

我的目的是创建一个表格,其中包含每种产品在两个不同年份的订单数量和收入。 我的想法是使用双左连接,但我不明白为什么这个查询在 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;

【问题讨论】:

  • 子查询可以独立执行吗?
  • 等等,MS-Access 没有一些特殊的双连接语法。
  • 子查询没问题。我可以单独运行它们
  • 今日提示:始终使用现代、明确的JOIN 语法!更容易编写(没有错误),更容易阅读和维护,如果需要更容易转换为外连接。
  • “不起作用”不是问题描述。如果其他一切都很好,您可能只是缺少了超过 2 个 JOIN 所需的括号。

标签: sql ms-access subquery left-join ms-access-2016


【解决方案1】:

您可以使用条件聚合来做到这一点:

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 年和/或 2014 年订购的产品,则可以将 LEFT 连接更改为 INNER 连接。

【讨论】:

  • 我认为数据模型在订单详情表中没有名为 FK_Prodcut_ID 的列。另外为什么你有从订单中选择的子查询?
  • 我认为数据模型在订单详情表中没有名为 FK_Prodcut_ID 的列 是什么意思?此列在 OP 的代码中,它是表 Orders 的外键。 MS Access 中需要子查询,因为它不支持 ON caluse 中的 AND ... IN (...) 等条件。
  • 谢谢!这真的很有帮助。其他查询也有效,但您的查询似乎更干净。
  • @forpas 我不认为它在那里,因为我看到产品加入订单,它加入订单详细信息——这是一个标准的明星模型——当然操作没有显示使用数据模型,所以我不能确定,但​​订单详细信息表和订单表都链接到产品表会很奇怪。并不是说它永远不会发生——只是我不希望它发生。如果是这样,那么您根本不需要加入订单表。
  • 再说一次,订单详情表和订单表都链接到产品表会很奇怪,这是什么意思?没有订单到产品的链接。
【解决方案2】:

这个查询没有意义。你说子查询运行良好——但他们不可能。尝试运行此查询

 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”不是表名的错误。

也许你是这个意思?

 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;

但是,我不会打扰两个子查询——甚至是 1 个子查询——它只会减慢你的速度——这样做:

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 中,您应该分组思考——第一组是订单……一年之后。

【讨论】:

  • 您的代码虽然是标准 SQL,但在 MS Access 中不起作用。
【解决方案3】:

您为什么不通过单个查询手动交叉表样式运行。我仅在订单表中查询 2013 年 1 月 1 日至 2015 年 1 月 1 日以下日期范围内的记录。这为我提供了 2 年内的所有订单,无论项目是否在一年内开始销售。

现在,我正在基于 IIF() 进行 sum()。如果订单的年份是 2013 年,则将 1 或 0 分别应用于它们的总数。 2014 年也是如此。根据构造和最终列名,这些应该是显而易见的。如果该记录不适用于该年份,则它只是零。总值也一样,我只是碰巧乘以 1 或 0。

唯一没有意义的是从产品表中获取单价。实际上,我会认为订单详细级别会有价格,因为多年来价格明显波动,我认为 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
        

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-25
    • 2015-11-03
    • 2015-08-25
    相关资源
    最近更新 更多