【问题标题】:How to Join tables without generating a 'combinatorial explosion' - MySQL如何在不产生“组合爆炸”的情况下加入表 - MySQL
【发布时间】:2021-07-21 01:01:31
【问题描述】:

我正在开发一个名为 classicmodels 的数据库。您可以在以下位置找到它:https://www.mysqltutorial.org/mysql-sample-database.aspx/

这家公司销售微型模型,分布在 7 个产品线中:老爷车、老爷车、飞机、卡车和公共汽车、飞机、火车和摩托车。

我想找出 2003 年和 2004 年最畅销的产品线(以销量和收入计)。

另外,我需要排除已取消的订单。这是由“订单”表中的“状态”列通知的。

因此,显然,我们必须连接三个表:“products”(按每个产品线对结果进行分组)、“orderdetails”(获取销售数量和单位价格)和“orders”(过滤结果) :仅选择 2003 年和 2004 年并排除已取消的订单)。

此外,需要说明的是,我们必须处理 1:M(一对多)对来解决这个问题,以避免组合/笛卡尔爆炸。

  • products --> orderdetails 是 1:M 关系

  • orderdetails --> 订单是1:M的关系

考虑到这一点,我决定创建子查询来建立 1:1 关系。所以,我计算了每个产品线的订购数量和总价值:

SELECT p.productLine, SUM(od.quantityOrdered) AS total_units, SUM(od.quantityOrdered*od.PriceEach) AS total_value
FROM products p
    JOIN
orderdetails od ON p.productCode=od.productCode
GROUP BY p.productLine
ORDER BY total_value DESC;

结果如下:

现在,我不知道如何将上述子查询生成的表与“订单”表连接起来。这是因为它们没有任何可用于 JOIN 的公共列。

如何确定 2003 年和 2004 年最畅销的产品线(以销量和收入计),不包括取消的订单?

您可以在下面检查数据库的关系模式:

【问题讨论】:

  • 你想达到什么目的?请分享表结构、示例输入数据以及与该示例数据对应的预期输出,并以文本形式(不是图像)分享所有这些信息
  • 从你的描述中,你想加入产品线,那么做吗?
  • @NicoHaase 好的!我将数据库的关系模式添加到帖子中。对不起,您所说的示例输入数据是什么意思?另外,我不知道如何将 MySQL 查询的输出共享为文本。但我会尝试

标签: mysql sql join cartesian-product


【解决方案1】:

只需在orders 表中添加另一个JOIN,并使用WHERE 条件来限制您想要的订单。

SELECT p.productLine, SUM(od.quantityOrdered) AS total_units, SUM(od.quantityOrdered*od.PriceEach) AS total_value
FROM products p
JOIN orderdetails od ON p.productCode=od.productCode
JOIN orders o ON o.orderNumber = od.orderNumber
WHERE o.orderDate BETWEEN '2003-01-01' AND '2004-12-31'
    AND o.status != 'cancelled'
GROUP BY p.productLine
ORDER BY total_value DESC;

【讨论】:

  • 'BETWEEN' 运算符是包容性的,对吗?我的意思是,计算中是否包括“2003-01-01”(开始日期)和“2004-12-31”(结束日期)?谢谢您的帮助!解决办法很明确!
  • 是的,你不能自己查一下吗?
  • 请注意,如果orderDate 包含时间,则应使用'2004-12-31 23:59:59' 作为范围的结尾。
  • @Barmar 好吧!我不知道我必须包括时间。但是,此数据库并非如此。非常感谢!
  • 如果省略时间默认为00:00:00,会错过最后一天。
【解决方案2】:

您不想将已有的结果加入到orders 表中,而是希望在聚合结果之前加入。

这只是在JOINs 列表的末尾添加另一个连接,然后使用WHERE 子句进行过滤,然后按照您的方式聚合...

SELECT
  p.productLine,
  SUM(od.quantityOrdered) AS total_units,
  SUM(od.quantityOrdered*od.PriceEach) AS total_value
FROM
  products       p
INNER JOIN
  orderdetails   od
    ON p.productCode = od.productCode
INNER JOIN
  orders         o
    ON o.orderNumber = od.orderNumber
WHERE
      o.status    != 'Cancelled'
  AND o.orderDate >= '2003-01-01'
  AND o.orderDate <  '2005-01-01'  -- Less than the next year, in case the date includes a time
GROUP BY
  p.productLine
ORDER BY
  total_value DESC;

【讨论】:

  • 我有一个疑问。 AND o.orderDate >= '2003-01-01' AND o.orderDate
  • &gt;= '2003-01-01'包容性的;其中包括从 2003 年初开始的所有内容。 &lt; '2005-01-01'ex专有的;其中包括 2005 年之前 的所有内容,甚至 2004 年的最后一个皮秒,但不包括 2005 年的任何时间,无论数据类型或数据粒度如何。
猜你喜欢
  • 2022-12-29
  • 2017-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-23
  • 2014-07-12
相关资源
最近更新 更多