【问题标题】:Order by and group by排序依据和分组依据
【发布时间】:2013-06-13 09:33:45
【问题描述】:

我正在尝试显示我正在建造的商店的运费,数据库中有三个表 1 用于服务,即皇家邮政、承运人......,一个用于乐队,即。 UK、Europe、Worldwide1 等。一个用于收费(数量 = 重量)

我有一个包含三个表的数据库,当它们连接时形成以下表格

+------------------+-----+-----------+-------+---------+---------------+----------+-------+-------------+
|       name       | qty | serviceID | basis | bandID | initial_charge | chargeID | price | total_price |
+------------------+-----+-----------+-------+---------+---------------+----------+-------+-------------+
| Collect in store |   0 |         3 |       |       1 | 3             | 0.00     | 2     | 0.00        |
| Royal mail       |   0 |         1 |     2 |       4 | 2.00          | 3        | 0.00  | 2.00        |
| Royal mail       |   1 |         1 |     2 |       4 | 2.00          | 4        | 1.00  | 3.00        |
| APC              |   0 |         2 |     1 |       1 | 0.00          | 6        | 5.95  | 5.95        |
+------------------+-----+-----------+-------+---------+---------------+----------+-------+-------------+

基本上我想做的是(如您所见)皇家邮政有两个条目,因为连接表中有多个条目。我想做的是显示两个皇家邮件条目中最高的条目(我最初尝试按 service_id 分组),同时还维护具有不同服务 ID 的其他两个服务

任何帮助都会很棒,因为这让我发疯。我觉得我已经尝试了所有组合!

在下面的示例中,物品的数量(重量)为 3kg

SELECT
    `service`.`name`,
    `charge`.`qty`,
    `service`.`serviceID`,
    `band`.`bandID`,
    `band`.`initial_charge`,
    `charge`.`chargeID`,
    `charge`.`price`,
    `band`.`initial_charge` + `charge`.`price` AS `total_price` 
FROM
    `delivery_band` AS `band` 
LEFT JOIN
    `delivery_charge` AS  `charge`
        ON 
            `charge`.`bandID` =  `band`.`bandID` 
        AND
            `charge`.`qty` <  '3'
LEFT JOIN
    `delivery_service` AS  `service`
        ON
            `service`.`serviceID` =  `band`.`serviceID` 
WHERE
    FIND_IN_SET(  '225',  `band`.`accepted_countries` ) 
AND
(
    `band`.`min_qty` >=  '3'
OR
    `band`.`min_qty` =  '0'
)
AND
(
    `band`.`max_qty` <=  '3'
OR
    `band`.`max_qty` =  '0'
)

delivery_service

+-----------+------------------+
| serviceID |       name       |
+-----------+------------------+
|         1 | Royal mail       |
|         2 | APC              |
|         3 | Collect in store |
+-----------+------------------+

delivery_band

+--------+-----------+-----------------+----------------+---------+---------+-------------------------------------------------------+
| bandID | serviceID |      name       | initial_charge | min_qty | max_qty |                  accepted_countries                   |
+--------+-----------+-----------------+----------------+---------+---------+-------------------------------------------------------+
|      1 |         2 | UK Mainland     | 0.00           |       0 |       0 | 225                                                   |
|      2 |         2 | UK Offshore     | 14.00          |       0 |       0 | 240                                                   |
|      3 |         3 | Bradford Store  | 0.00           |       0 |       0 | 225                                                   |
|      4 |         1 | UK              | 2.00           |       0 |       0 | 225                                                   |
|      5 |         2 | World wide      | 15.00          |       0 |       0 | 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20... |
|      6 |         1 | World wide Mail | 5.00           |       0 |       0 | 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20... |
+--------+-----------+-----------------+----------------+---------+---------+-------------------------------------------------------+

delivery_charge

+----------+--------+-----+-------+
| chargeID | bandID | qty | price |
+----------+--------+-----+-------+
|        1 |      2 |   0 | 5.00  |
|        2 |      3 |   0 | 0.00  |
|        3 |      4 |   0 | 0.00  |
|        4 |      4 |   1 | 1.00  |
|        5 |      4 |   5 | 3.00  |
|        6 |      1 |   0 | 5.95  |
|        7 |      1 |  10 | 10.95 |
|        8 |      2 |  10 | 14.00 |
|        9 |      5 |   0 | 0.00  |
|       10 |      5 |   3 | 5.00  |
|       11 |      5 |   6 | 10.00 |
|       12 |      5 |   9 | 15.00 |
|       13 |      6 |   0 | 0.00  |
|       14 |      6 |   2 | 5.00  |
|       15 |      6 |   4 | 10.00 |
|       16 |      6 |   6 | 15.00 |
+----------+--------+-----+-------+

当我尝试将费用表添加为子查询然后限制该查询时,它给了我所有费用表字段的 NULL

如果我尝试以下查询:

SELECT
    `service`.`name`,
    `charge`.`qty`,
    `service`.`serviceID`,
    `band`.`bandID`,
    `band`.`initial_charge`,
    `charge`.`chargeID`,
    MAX( `charge`.`price` ) AS `price`,
    `band`.`initial_charge` + `charge`.`price` AS `total_price` 
FROM
    `delivery_band` AS `band` 
LEFT JOIN
    `delivery_charge` AS  `charge`
        ON 
            `charge`.`bandID` =  `band`.`bandID` 
        AND
            `charge`.`qty` <  '3'
LEFT JOIN
    `delivery_service` AS  `service`
        ON
            `service`.`serviceID` =  `band`.`serviceID` 
WHERE
    FIND_IN_SET(  '225',  `band`.`accepted_countries` ) 
AND
(
    `band`.`min_qty` >=  '3'
OR
    `band`.`min_qty` =  '0'
)
AND
(
    `band`.`max_qty` <=  '3'
OR
    `band`.`max_qty` =  '0'
)
GROUP BY
    `service`.`serviceID`

我得到这个返回:

+------------------+-----+-----------+--------+----------------+----------+-------+-------------+
|       name       | qty | serviceID | bandID | initial_charge | chargeID | price | total_price |
+------------------+-----+-----------+--------+----------------+----------+-------+-------------+
| Royal mail       |   0 |         1 |      4 | 2.00           |        3 | 1.00  | 2.00        |
| APC              |   0 |         2 |      1 | 0.00           |        6 | 5.95  | 5.95        |
| Collect in store |   0 |         3 |      3 | 0.00           |        2 | 0.00  | 0.00        |
+------------------+-----+-----------+--------+----------------+----------+-------+-------------+

这在原则上看起来不错,直到您意识到chargeID = 3 的价格为 0.00,但表格显示的价格为 1.00,因此这些值似乎已解除​​关联

【问题讨论】:

  • sqlfiddle.com/#!2/9665c4/4 - 你能看出问题所在吗? - 谢谢你的链接顺便说一句 - 不知道这存在!
  • 小提琴是为了让人们可以在得出结果的同时玩弄您的数据。您最初的问题没有明确说明您不仅想要最高价格,而且还想要 id 与之配套。我想现在应该更清楚了。
  • 很抱歉 :( 我猜这是在我的脑海里,但没有传达出来

标签: mysql join group-by sql-order-by


【解决方案1】:

我想做的是显示两个皇家邮件条目中最高的一个

您可以使用MAX 来获取给定列的最大值,例如

SELECT … MAX(charge.price) … FROM …

如果您绝对需要其他列(如charge.chargeID)来匹配,事情会变得很多更复杂。因此,请确保您确实需要它。有关此类查询背后的一般思想的详细信息,请仔细查看Select one value from a group based on order from other columns。通过@RichardTheKiwi 改编this answer,我想出了以下查询:

SELECT s.name,
       c.qty,
       s.serviceID,
       b.bandID,
       b.initial_charge,
       c.chargeID,
       c.price,
       b.initial_charge + c.price AS total_price
FROM delivery_band AS b,
     delivery_service AS s,
    (SELECT chargeID, price, qty,
            @rowctr := IF(bandId = @lastBand, @rowctr+1, 1) AS rowNumber,
            @lastBand := bandId AS bandId
     FROM (SELECT @rowctr:=0, @lastBand:=null) init,
          delivery_charge
     WHERE qty < 3
     ORDER BY bandId, price DESC
    ) AS c
WHERE FIND_IN_SET(225, b.accepted_countries)
  AND (b.min_qty >= 3 OR B.min_qty = 0)
  AND (b.max_qty <= 3 OR B.max_qty = 0)
  AND s.serviceID = b.serviceID
  AND c.bandID = b.bandID
  AND c.rowNumber = 1

请参阅this fiddle 以获取相应的输出。请注意,我只进行内部查询,而不是左查询,因为这对于相关查询来说似乎已经足够了,并且使事情更具可读性,因此您可以专注于重要部分,即那些涉及 rowNumber 的部分。这个想法是子查询为同一波段的项目生成行号,为下一个波段重置它们。当您仅选择 rowNumber 为 1 的行时,您只会获得最高价格,与所有其他列相关的列

【讨论】:

  • 伟大的开始。然而,发现了一个小问题,MAX(charge.price) 和 GROUP BY service.serviceId 给了我正确的答案。然而,它失去了charge_id的关联。所以它给了我最高的价格,但与表中价格来源无关的charge_id
  • 我在原始问题中添加了更多内容,因为我无法完整回复评论
  • @Eth:我的原始答案明确指出MAX 只会影响单个列,不会导致其他列与之匹配。那时,还不清楚您是否真的需要其他列来匹配。在您发表评论后,我已通过详细查询更新了我的答案以完成此操作。
  • 抱歉,一开始不够清楚。你已经破解了 - 谢谢:-)
猜你喜欢
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-24
  • 1970-01-01
  • 2013-09-14
  • 1970-01-01
  • 2010-09-06
相关资源
最近更新 更多