【问题标题】:How to write custom MySQL select query for orders and their items如何为订单及其项目编写自定义 MySQL 选择查询
【发布时间】:2015-10-26 21:30:47
【问题描述】:

我已尽我所能详细描述我的问题;如果您有任何问题,请发表评论并询问。我知道我可能错过了一个非常简单的解决方案,并且很想听听我怎样才能使它变得更简单;也就是说,请确保您的答案考虑了我所描述的所有内容,并且在发布您的解决方案之前,您已经提出了所有问题(并收到了答案)。

背景

两个表:ordersitems,每个表都包含唯一信息(它们使用 ID 相互连接;没有重复数据)。见附件 A 和 B(下)。

orders 表(附件 A)包含该订单独有的所有信息。添加到订单中的每个商品在表中都有自己的行,包含订单 ID、商品 ID 和数量(以及其他不相关的字段)。

问题

我正在构建一个界面,允许用户通过以下参数过滤订单:

  • 商品数量(产品)
  • 件数(产品数量)
  • 成本(总订单成本:产品数量乘以产品成本)

在我看来,在单个 MySQL 查询中收集所有数据应该是可能的。这是我需要收集的信息:

  • 每个订单的商品数量
  • 项目 ID
  • 购买数量(每件产品)

示例

用户希望按以下规格过滤所有订单:

  • 三项(产品)
  • 七件(总量)
  • 不到 600 美元

如果所有数据(订单和商品)都包含在一个表中,则查询将是这样的:

SELECT order_ID, 
       GROUP_CONCAT(item_ID) as item_IDs, 
       GROUP_CONCAT(quantity) as quantities, 
       SUM(price) as price 
FROM orders 
GROUP BY order_ID 
HAVING 7 = SUM(quantity) AND 
       3 = COUNT(*)

并返回如下内容:

order_ID | item_IDs | quantities | price
=========================================
15       | 22,9,36  | 1,4,2      | $582

但由于价格存储在单独的表中,所以比较复杂。我创建了这个查询(参见图表 C):

SELECT DISTINCT o.order_ID, 
       GROUP_CONCAT(o.`item_ID`) as item_IDs,
       GROUP_CONCAT(o.`quantity`) as quantities 
FROM orders o 
GROUP BY o.`order_ID` 
HAVING 7 = SUM(o.`quantity`) AND 
       3 = COUNT(*) 
ORDER BY o.`order_ID` DESC`

这让我很接近,但让我想要定价信息。我尝试过使用JOINS (What's the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN and FULL JOIN?),但下班后无法正常工作。

问题

是否可以在一个 MySQL 查询中检索所有这些数据,和/或是否有比我目前使用的路径更好的方法(你会怎么做)?

查询返回类似于以下的结果是可以接受的:

order_ID | item_ID | quantity | price
======================================
177      | 42      | 2        | 50.00
177      | 45      | 3        | 30.00
177      | 46      | 2        | 10.00
150      | 39      | 3        | 25.00
150      | 47      | 1        | 95.00
150      | 41      | 3        | 15.00

只要查询要求生成的订单包含三件商品和七件商品,并且总额低于 600 美元(根据提供的示例)。

我也辞职了,这在一个查询中可能是不可能的,并且我知道如何使用 PHP 来完成它;我想我可能会尽可能在 MySQL 中做很多事情,并在今天学习一些东西。 :)

你们中的一些人可能会建议更改表结构,但如果可以提供帮助,我真的宁愿不要有重复数据的表:如果产品价格发生变化,我宁愿不必在两个表中更新。

感谢您抽出宝贵的时间以及您可能拥有的任何解决方案;我非常感谢你们能提供的任何帮助。

展品/视觉教具

展品 A:orders 桌子

ID    | order_ID | item_ID | quantity
======================================
1146  | 195      | 52      | 3
1145  | 195      | 1       | 4
1142  | 193      | 41      | 1
1141  | 193      | 40      | 3
1031  | 177      | 45      | 3
1032  | 177      | 46      | 2
1030  | 177      | 42      | 2
881   | 150      | 47      | 1
880   | 150      | 39      | 3
882   | 150      | 41      | 3

展品 B:items

(提供完整性,非关键信息) https://cldup.com/ZQEDy-vef6.png

图表 C:查询和结果

SELECT DISTINCT o.order_ID, 
       GROUP_CONCAT(o.`item_ID`) as item_IDs,
       GROUP_CONCAT(o.`quantity`) as quantities 
FROM orders o 
GROUP BY o.`order_ID` 
HAVING 7 = SUM(o.`quantity`) AND 
       3 = COUNT(*) 
ORDER BY o.`order_ID` DESC

.

order_ID | item_IDs | quantities
=================================
177      | 42,45,46 | 2,3,2
150      | 39,47,41 | 3,1,3
115      | 39,47,41 | 3,1,3
108      | 48,45,46 | 2,3,2

图表 D:SQLFiddle

http://sqlfiddle.com/#!9/2763f5

【问题讨论】:

    标签: mysql join count sum having


    【解决方案1】:

    从这里开始,一步一步完成。

    第一件事是LEFT JOIN是你的朋友。所以你可以得到每件商品的价格

    示例 1:

    通过此查询,您可以从表格订单中获取前 100 行,包括每个订单的价格。

    SELECT o.order_ID, 
           o.item_ID as item_ID,
           o.quantity as quantitie,
           i.price
    FROM orders o
    LEFT JOIN items i ON o.item_ID = i.id
    ORDER BY o.order_ID
    LIMI 100;
    

    示例 2:

    现在您的查询必须分成两部分。首先,我们将获取所有符合您的条件(商品、件数和价格)的订单 ID

         SELECT o.order_ID
            FROM orders o
            LEFT JOIN items i ON o.item_ID = i.id
            GROUP BY o.order_ID
            HAVING
             SUM(o.`quantity`) =7 
           AND
             SUM(1) = 3
           AND
             SUM(i.price) < 700;
           ORDER BY o.order_ID;
    

    示例 3:

    现在他拥有了所有的 order_id 并且可以结合这两个查询。

    SELECT o.order_ID, 
           o.item_ID as item_ID,
           o.quantity as quantitie,
           i.price
    FROM orders o
    LEFT JOIN items i ON o.item_ID = i.id
    where o.order_ID IN (
        SELECT o.order_ID
        FROM orders o
        LEFT JOIN items i ON o.item_ID = i.id
        GROUP BY o.order_ID
        HAVING
         SUM(o.`quantity`) =7 
       AND
         SUM(1) = 3
       AND
         SUM(i.price) < 700    )
    ORDER BY o.order_ID, o.quantity, i.price;
    

    但是这不是 testet。如果您通过 sqlfile 输入一些示例日期,那么我可以直接为您测试。

    示例 4

    我已将最后一个查询更改为 LEFT JOINS,但它不适用于小提琴。我有一个超时。请在您的服务器上检查。

    我还看到您的表格上没有良好的索引。所以查询可能会非常慢

      SELECT mo.order_ID, 
            mo.item_ID ,
            mo.quantity,
            mi.price
       FROM (
            SELECT o.order_ID
            FROM orders o
            LEFT JOIN items i ON o.item_ID = i.id
            GROUP BY o.order_ID
            HAVING
             SUM(o.`quantity`) =7 
           AND
             SUM(1) = 3
           AND
             SUM(i.price) < 700 
        ) AS ord
        LEFT JOIN orders mo ON ord.order_ID = mo.order_ID
        LEFT JOIN items  mi ON mo.item_ID = mi.id
        ORDER BY ord.order_id, mo.quantity, mi.price;
    

    结果

    +----------+---------+----------+--------+
    | order_ID | item_ID | quantity | price  |
    +----------+---------+----------+--------+
    |      115 |      47 |        1 |  30.00 |
    |      115 |      41 |        3 |  42.00 |
    |      115 |      39 |        3 |  60.00 |
    |      150 |      47 |        1 |  30.00 |
    |      150 |      41 |        3 |  42.00 |
    |      150 |      39 |        3 |  60.00 |
    |      177 |      46 |        2 | 120.00 |
    |      177 |      42 |        2 | 120.00 |
    |      177 |      45 |        3 | 180.00 |
    +----------+---------+----------+--------+
    9 rows in set (0.06 sec)
    

    【讨论】:

    • 哇,反应快;谢谢你!我已经添加了一个 SQLFiddle 作为 Exhibit D。从我读过的内容来看,子查询不是一个很好的性能选项......但我猜因为这就是你回答的内容,没有子查询就不可能获得首选输出?
    • 我有 testet 样本 3,输出对我来说似乎不错。你也可以用更多的LEFT JOINS来做到这一点。我会做一个样品
    • 我也用完整的数据库进行了测试,输出看起来很完美!非常感谢您提供有效的解决方案。我很想知道是否可以不使用子查询。
    • @Caleb 我添加了示例 4
    • 执行示例 4 时:MySQL 错误 #1248 - 每个派生表都必须有自己的别名
    猜你喜欢
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 2012-12-22
    • 2015-11-02
    • 1970-01-01
    • 1970-01-01
    • 2019-06-27
    • 1970-01-01
    相关资源
    最近更新 更多