【问题标题】:MYSQL JOIN and SUM - What am I doing wrong? [closed]MYSQL JOIN 和 SUM - 我做错了什么? [关闭]
【发布时间】:2021-04-02 15:51:51
【问题描述】:

我已经用尽了所有的选择。我不明白我哪里出了问题。请帮我。我不能接受更多的头撞。这就是我所在的地方...

下面是我的表结构的解释。

locations_management
包含将locations_management_id、season_id、location_id和其他不需要的信息链接在一起的数据

订单
包含有关订单的数据,包括 location_management_id 和 order_id 以及其他不需要的信息

orders_products
通过 order_id 链接到订单的产品数据。此表仅使用以下列:order_product_id、order_id、product_id、piece_qty

orders_adjustments
用于跟踪对 inv_shipped 的任何调整。此表使用 order_id、product_id、piece_qty 列

这就是我今天所处的位置。下面的查询从上面的表中提取数据。

基本上,我要求从 locations_management 表 WHERE season_id = 12 AND location_id = 35 中获取 location_management_id。可以有多个可能的 location_management_id 同时适合 season_id 和 location_id。然后我需要找到与这些 location_management_id(s) 匹配的订单。找到订单后,我需要使用 order_id(s) 在 orders_products 表中查找与其关联的产品。 这个查询正是这样做的,但是当我进一步合并/求和时 piece_qty 为总 inv_shipped,数字发生了疯狂的事情。

SELECT  
    locations_management.season_id,  
    locations_management.location_id,  
    orders.order_id,  
    orders_products.product_id,  
    IFNULL((orders_products.piece_qty), 0) AS inv_shipped,  
    IFNULL((orders_adjustments.piece_qty), 0) AS inv_adjustments  
FROM  
    locations_management  
    JOIN orders USING (location_management_id)  
    LEFT JOIN orders_products USING (order_id)  
    LEFT JOIN orders_adjustments ON (orders_adjustments.order_id = orders_products.order_id) AND (orders_adjustments.product_id = orders_products.product_id)  
WHERE  
    locations_management.season_id = 12 AND locations_management.location_id = 35  
GROUP BY   
    product_id, orders_products.order_id

当我运行上面的查询时,这就是我得到的......

season_id   location_id     order_id    product_id      inv_shipped     inv_adjustments
12          35              2127        1               220             0
12          35              2194        1               160             0
12          35              2127        3               312             0
12          35              2127        4               24              0
12          35              2127        5               180             0
12          35              2194        5               24              0
12          35              2127        7               144             0
12          35              2127        7               24              0

这正是我期望得到的。多个 order_id 由 product_id 分组,所有数据都是准确的。所以现在这里成了问题。我想在 product_id 匹配并具有组合的 inv_shipped 时将它们添加/求和。所以 product_id 1 现在 inv_shipped 的总数为 380。

当我从上面获取相同的查询并将 SUM 添加到 inv_shipped 和 inv_adjustments(如下所示)时,我会在下面得到这个数据输出。注意一些值是如何翻倍的,但匹配的 product_id 行也没有合并。

    IFNULL(SUM(orders_products.piece_qty), 0) AS inv_shipped,  
    IFNULL(SUM(orders_adjustments.piece_qty), 0) AS inv_adjustments  

season_id   location_id     order_id    product_id      inv_shipped     inv_adjustments
12          35              2127        1               440             0
12          35              2194        1               160             0
12          35              2127        3               624             0
12          35              2127        4               48              0
12          35              2127        5               360             0
12          35              2194        5               24              0
12          35              2127        7               288             0
12          35              2127        7               24              0

如果我只将 GROUP BY 更改为 product_id,我会得到以下数据:

    GROUP BY product_id  

season_id   location_id     order_id    product_id      inv_shipped     inv_adjustments
12          35              2127        1               600             0
12          35              2127        3               624             0
12          35              2127        4               48              0
12          35              2127        5               384             0
12          35              2127        7               312             0

同样,这些 inv_shipped 总数不正确。那我哪里错了?

------------------------------------ 建议 ---------- --------------------------

建议使用以下查询,但 inv_shipped 的数据输出也未正确添加。

SELECT 
    locations_management.season_id,
    locations_management.location_id,
    orders.order_id,
    products.product_id,
    products.inv_shipped 
FROM
    locations_management
    JOIN (SELECT location_management_id, order_id FROM orders group by order_id) AS orders ON orders.location_management_id = locations_management.location_management_id
    JOIN (SELECT order_id, product_id, IFNULL(SUM(piece_qty), 0) AS inv_shipped FROM orders_products GROUP BY order_id, product_id) AS products ON products.order_id = orders.order_id

WHERE
    locations_management.season_id = 12 AND locations_management.location_id = 35
ORDER BY 
    product_id, order_id  
    
season_id   location_id     order_id    product_id      inv_shipped     inv_adjustments
12          35              2127        1               440             0
12          35              2194        1               160             0
12          35              2127        3               624             0
12          35              2127        4               48              0
12          35              2127        5               360             0
12          35              2194        5               24              0
12          35              2127        7               288             0
12          35              2127        7               24              0

【问题讨论】:

  • products 子查询中聚合(计算每个 product_id 的 SUM),而不是在外部查询中。
  • 您好,谢谢您,我已经尝试过此更改。我得到相同的结果。请参阅下面的我的 cmets 到 tcadidot0 的帖子。我将详细介绍该问题以及解决问题时可以看到的内容。
  • 请在代码问题中给出minimal reproducible example--cut & paste & runnable code,包括最小的代表性示例输入作为代码;期望和实际输出(包括逐字错误消息);标签和版本;明确的规范和解释。对于包含 DBMS 和 DDL(包括约束和索引)和输入为格式化为表的代码的 SQL。 How to Ask 以意外结果切入第一个子表达式并解释您的期望和原因,并提供理由参考文档。
  • 在扩展到问题代码之前(几乎)提供工作代码非常好,但是在您的 2 个连接之后首先使用 select * 来查看您正在聚合的内容。这里的第一条评论是正确的。这有一个常见的错误,人们想要一些连接,每个可能涉及不同的键,一些子查询,每个可能涉及连接和/或聚合,但他们错误地尝试先进行所有连接,然后再进行所有聚合或聚合以前的聚合.在适当的行上写单独的总和和/或总结一个案例语句选择行;加入常见的唯一列集。
  • 在给出关系(船舶)/关联或表(基本或查询结果)时,说明其中的一行根据其列值说明了业务情况。查询不需要约束,表含义(根据前面的句子)是足够和必要的。但是,如果查询依赖于某些约束,请给出它们。当你得到一个意外/“错误”的结果时,暂停你的总体目标并调试你的误解。 PS“基本上”或“基本上”或“换句话说”,没有引入或总结清晰、准确和完整的描述,也只是表示“不清楚”。

标签: mysql join group-by sum


【解决方案1】:

首先,找到问题的根源。正确和错误信息之间有什么变化?

让我们看看您的第二个查询。据我所知,有三件事发生了变化:

  1. 您已加入另一个子查询。
  2. 您已添加SUM 操作。
  3. 您已添加GROUP BY

嵌套步骤是尝试删除SUMGROUP BY,如下所示:

SELECT 
    locations_management.season_id AS season_id,
    locations_management.location_id AS location_id,
    orders.order_id AS order_id,
    products.product_id AS product_id,
    products.piece_qty
FROM
    locations_management
    JOIN (SELECT location_management_id, order_id FROM orders group by order_id) AS orders ON orders.location_management_id = locations_management.location_management_id
    JOIN (SELECT order_id, product_id, piece_qty FROM orders_products) AS products ON products.order_id = orders.order_id

WHERE
    locations_management.season_id = 12 AND locations_management.location_id = 35

我假设每个product_id 将返回两(或更多)行。这可能是因为您的第二个JOINorders_products 表中有两个(或更多)行order_id;这似乎很明显,因为表orders 的第一个子查询具有group by order_id。所以,现在要快速解决这个问题,您需要在第二个子查询中执行SUM。像这样的:

SELECT 
    locations_management.season_id AS season_id,
    locations_management.location_id AS location_id,
    orders.order_id AS order_id,
    products.product_id AS product_id,
    products.inv_shipped 
FROM
    locations_management
    JOIN (SELECT location_management_id, order_id FROM orders group by order_id) AS orders ON orders.location_management_id = locations_management.location_management_id
    JOIN (SELECT order_id, product_id, IFNULL(SUM(products.piece_qty), 0) AS inv_shipped FROM orders_products GROUP BY order_id, product_id) AS products ON products.order_id = orders.order_id

WHERE
    locations_management.season_id = 12 AND locations_management.location_id = 35;

这可能会返回正确的结果,但我个人会这样编写查询:

SELECT lm.season_id, lm.location_id, o.order_id , p.product_id, p.inv_shipped 
FROM locations_management AS lm
JOIN (SELECT location_management_id, order_id 
      FROM orders 
      GROUP BY location_management_id,order_id) AS o 
  ON o.location_management_id = lm.location_management_id
JOIN (SELECT order_id, product_id, IFNULL(SUM(products.piece_qty), 0) AS inv_shipped 
      FROM orders_products 
      GROUP BY order_id, product_id) AS p 
  ON p.order_id = o.order_id
WHERE
    lm.season_id = 12 AND lm.location_id = 35;
  1. 如果您的别名与列名相同,则无需设置别名;例如lm.season_id AS season_id。如果您删除 .. AS season_id,该列仍将被识别为 season_id。您不会将其视为lm.season_id.. 至少对于我所知道的大多数工具而言。此外,我个人认为别名旨在缩短长表或列名,但 "to each their own"
  2. GROUP BY 应包括 SELECT 中的所有非聚合列。当然,如果sql_mode=only_full_group_by 关闭,您可以运行查询,但正确的设置应该是ON。你可以阅读更多of the reason why here
  3. GROUP BY 中添加额外的列后,此查询可能不会返回您曾经拥有的结果。这取决于您的数据,如果发生这种情况,我建议您edit your question 并添加Minimal, reproducible example。目前,我们只看到查询,没有可使用的示例表/数据。如果你能用几行数据create a fiddle就更好了。

【讨论】:

  • 非常感谢您花时间帮助我! “正确信息和错误信息之间有什么变化?”因此,当我将修改后的查询与两个 JOIN 一起使用时,输出的数据正是我想要的。当存在两个或更多订单时,这些订单会按其匹配的 product_id 和 SUM 组合在一起。上面的第一个输出显示了我如何将位置表连接到订单表以根据 season_id 和 location_id 获取 order_ids。然后我添加了第二个连接以从 orders_products 表中提取所有具有匹配 order_ids 的产品。
  • 当我查询 season_id AND location_id 并且该数据包含带有产品数据的订单时,inv_shipped 是正确的。从我可以排除的故障来看,这种不正确的 SUM'ing 仅在有一个尚未实际分配的订单 (orders_products) 的订单 (order_id) 时发生。订单存在于订单表中,但尚未分配任何产品。另一方面,当我用每个 order_id 的产品查询一个 season_id AND location_id 时,每个 product_id 的组合 SUM 是正确的。您修改后的两个查询都返回了我得到的相同结果。
  • 那么你的意思是,在order_products 表内部,可能会重复order_id,但没有分配product_id,但piece_qty 的值存在?如果是这样,您也许可以将 sum 语法更改为 IFNULL(SUM(CASE WHEN product_id IS NULL THEN 0 ELSE piece_qty END), 0) ..(更改 IS NULL,具体取决于 product_id 的默认未分配值)。看看这是否可行
【解决方案2】:

我认为不需要那些嵌套的子查询。如果您希望每个订单和产品有一行,则可能不需要聚合。

你似乎想要这不是你想要的吗?

select lm.season_id, lm.location_id, 
    op.order_id, op.product_id, op.piece_qty as inv_shipped
from locations_management lm
inner join orders o on o.location_management_id = lm.location_management_id 
inner join order_products op on op.order_id = o.order_id
where lm.season_id = 12 and lm.location_id = 35

或者,如果您希望每个产品有一行:

select lm.season_id, lm.location_id, 
    op.product_id, coalesce(sum(op.piece_qty), 0) as inv_shipped
from locations_management lm
inner join orders o on o.location_management_id = lm.location_management_id 
left join order_products op on op.order_id = o.order_id
where lm.season_id = 12 and lm.location_id = 35
group by lm.season_id, lm.location_id, op.product_id

【讨论】:

  • 感谢您抽出宝贵时间帮助我,我同意不应该需要它们,但正如我在过去几天里搜索过 SUM 会错误地输出总计的原因一样,直接 JOIN 是最常用的常见问题。上面的查询只是我多次迭代中的最新一次。请看我上面的cmets
  • 您的第一个查询想法会输出分配给每个 order_id 的所有产品行。它不会根据它们的 product_id 将它们组合/求和。第二个查询与我上面的原始示例完全一样。当所有订单都有产品时,inv_shipped 是正确的 SUM'c。如果存在一个订单但尚未分配产品,则根据存在的订单数量将 inv_shipped 添加到自身。
  • @DavidK:我不明白你的意思。第二个查询过滤掉没有产品的订单。如果您愿意,可以使用left join 保留它们。我在代码中更改了它。
  • 你好专线小巴。我完全编辑了上面的原始帖子,以提供有关表格以及如何使用数据的更多详细信息。请看一下,也许这会让事情更容易理解。
  • @DavidK:请同时显示您想要的结果。
猜你喜欢
  • 1970-01-01
  • 2012-11-07
  • 2013-02-08
  • 2018-11-04
  • 2014-05-14
  • 2014-09-13
  • 2014-02-16
  • 2018-01-22
  • 1970-01-01
相关资源
最近更新 更多