MySQL - 查找来自多个供应商的商品的最新、最优惠价格

Posted

技术标签:

【中文标题】MySQL - 查找来自多个供应商的商品的最新、最优惠价格【英文标题】:MySQL - Find most recent, best price for item from multiple vendors 【发布时间】:2018-12-07 22:24:15 【问题描述】:

我目前无法为我的问题找到解决方案,你们是我最后的希望。两天以来,我一直在尝试解决这个难题:

表项:

----------------------------
| id   | item   | customer |
----------------------------
| 1    | banana | custA    |
----------------------------
| 2    | apple  | custA    |
----------------------------
| 3    | orange | custB    |
----------------------------
| 4    | apple  | custB    |
----------------------------

表 vendor_prices:

-------------------------------------------------------
| id  |   item    |   price   |   vendor |  timestamp |
-------------------------------------------------------
| 1   |  banana   |   0.23    | VendorA  |  564645564 |
-------------------------------------------------------
| 2   |  orange   |   0.21    | VendorA  |  564645564 |
-------------------------------------------------------
| 3   |  apple    |   0.19    | VendorB  |  564645564 |
-------------------------------------------------------
| 4   |  banana   |   0.22    | VendorB  |  564645565 |
-------------------------------------------------------
| 5   |  banana   |   0.21    | VendorB  |  564645567 |
-------------------------------------------------------

有几点需要注意:

    并非每个供应商都有每件商品 某些供应商可能会比其他供应商更频繁地更新其价格,从而导致它们之间的时间戳差距更大

例如,我想知道目前哪个供应商以最优惠的价格出售香蕉?

我想我首先需要从每个供应商那里获取每件商品的最新价格,然后按价格对它们进行排序,对吗?但是如何以兼容 mysql 的方式做到这一点呢?

我认为第一部分的正确方法是:

SELECT MAX(timestamp), vendor, item, MIN(price) FROM vendor_prices WHERE item="banana" GROUP BY vendor;

但是如何将它与所有其他标准联系起来呢?

编辑:我不得不稍微更改第一个表,因为我忘记了问题中的一个重要部分,抱歉:(

预期输出:所有供应商针对第一个表中特定客户(custA 或 custB)的所有商品的最新最优价格

【问题讨论】:

这样的? db-fiddle.com/f/rsEk3TyyDBy3Qpsxb6RDVT/0 添加香蕉项目的预期输出 @Hackerman 这确实会生成重复条目,如果两个供应商的时间戳相同(可能发生):( 【参考方案1】:

您可以使用嵌套的groupwise maximum logic 作为您的标准

select a.*
from vendor_prices a
join (
  select item, min(price) price, max(timestamp) timestamp
  from (
    select d.*
    from vendor_prices d
    join (
      select item, vendor, max(timestamp) timestamp
      from vendor_prices
      group by item, vendor
    ) e using(item, vendor,timestamp )
  ) c
  group by item
) b using (item,price, timestamp)
where a.item = 'banana'

Demo

如果您使用的是 Mysql 8+,则可以使用窗口函数受益

编辑 *获取客户的所有商品(每件商品的最佳价格和供应商)*

select  i.*,a.*
from vendor_prices a
join (
  select  item, min(price) price, max(timestamp) timestamp
  from (
    select  d.*
    from vendor_prices d
    join (
      select  item, vendor, max(timestamp) timestamp
      from vendor_prices
      group by item, vendor
    ) e using(item, vendor,timestamp )
  ) c
  group by item
) b using (item,price,timestamp )
join item i using(item)
where i.customer = 'custA'
order by i.item

Demo

使用 Mysql 8 中可用的 window function 和 common table expression,您可以使用以下

with latest_price as(
    select *, 
    dense_rank() over (partition by item order by timestamp desc, price asc ) rnk
    from vendor_prices
    order by  item, rnk
)

select i.id itemid, i.customer,a.* 
from latest_price a
join item i using(item)
where i.customer = 'custA'
and a.rnk = 1

Demo

【讨论】:

我不知道为什么这被否决了,因为它产生了正确的结果。 这似乎可行,但看起来它对数据库很重。我目前在 vendor_prices 中有 146k 行,并且查询已经花费了 0.15 秒来获取 1 项。但也许这很正常。不幸的是,我忘记了我的问题中的一个重要部分。第一个表还有一个客户列。我的目标是为客户获取所有商品(每件商品的最佳价格和供应商)。对不起,我的错误,我的大脑正在泄漏...... @nim 是的,上面的查询对于 DB 来说太重了,但是在 Mysql 中,如果你可以使用像 Mysql 8 这样的新版本,它支持窗口函数并使用实际上为这样的窗口函数问题可以为您带来更好的表现,对于您与客户相关的问题,我已经更新了我的答案,其中仅包含与项目表的连接,这样您将客户的所有项目(每个项目的最佳价格和供应商) @fubar 我知道那个投反对票的用户,几乎在我的大部分答案中,我猜有一些嫉妒因素,他太害羞/害怕提到他投反对票的正当理由,但我真的不在乎,我只是尽可能地专注于为这个社区做出贡献。 @M Khalid Junaid:感谢您提供的示例。但是,我在我的系统上尝试了代码,它返回了很多重复项。我认为这是由于速度很快,多个供应商对一个项目具有相同的时间戳是很有可能的。我在您的示例中添加了更多数据,那里也发生了同样的情况:sqlfiddle.com/#!9/ea19a9/1

以上是关于MySQL - 查找来自多个供应商的商品的最新、最优惠价格的主要内容,如果未能解决你的问题,请参考以下文章

mysql必知必会(13章)

来自连接表的 MySQL 更新语句(受该表的最新值限制)

来自多个表的 MySQL 最新相关记录

从分组方式中排除列

存储来自多个查找表的用户配置文件数据。如何?

[jsp+mysql]网络物流系统