如何在 MySQL < 8.0 中模拟窗口函数
Posted
技术标签:
【中文标题】如何在 MySQL < 8.0 中模拟窗口函数【英文标题】:How to emulate window functions in MySQL < 8.0 【发布时间】:2019-11-24 14:53:34 【问题描述】:我有这样的表格:
INSERT INTO listings
(id, external_id, variation_id, product_id) VALUES
(101, '9900001', '9900001var1', 1),
(102, '9900001', '9900001var2', 4),
(103, '9900002', '9900002var1', 1),
(104, '9900002', '9900002var2', 2),
(105, '9900003', '9900003var1', 3),
(106, '9900003', '9900003var2', 4);
INSERT INTO products
(id, price) VALUES
(1, 101),
(2, 100),
(3, 100),
(4, 102);
这意味着有 3 个列表(9900001、9900002、9900003),每个列表分别包含 2 个产品(1、4)、(1、2)和(3、4)。
我需要为每个列表检索一行,其中包含该列表中价格最高的产品的 ID(不是价格)。
因此,所需的输出将是:
id | external_id | variation_id | product_id
[ANY] 9900001 [ANY] 4
[ANY] 9900002 [ANY] 1
[ANY] 9900003 [ANY] 4
我得到的最接近所需答案的是这个查询:
SELECT
p.id AS product_id_max,
p.price AS product_price_max,
MAX(p.price) AS product_price_max_max,
listings.*
FROM listings
INNER JOIN (
-- Subquery tested above:
SELECT DISTINCT pp3.* FROM
(SELECT MAX(p2.price) as max_price
FROM products p2
INNER JOIN listings l2 ON l2.product_id = p2.id
GROUP BY l2.external_id) pp2
INNER JOIN
(SELECT p3.* FROM products p3 ) pp3
ON
pp2.max_price = pp3.price
ORDER BY pp3.price DESC
) AS p
ON p.id = listings.product_id
-- WHERE MAX(p.price) = p.price
GROUP BY external_id
-- HAVING MAX(p.price) = p.price
ORDER BY product_price_max DESC
取消注释 WHERE 子句会引发错误,取消注释 HAVING 子句返回的行数少于所需的行数。 Levin 都评论说在 product_id 列中给出了正确的行但错误的值。
小提琴:http://sqlfiddle.com/#!9/d58d665/54/0
【问题讨论】:
@bill-karwin 您发布的链接回答了不同的问题。听起来相似,但问题不同。 好的,我把重复问题的链接倒过来了。我会留下greatest-n-per-group 标签,因为它属于一般类型的问题。 自从 mysql 8.0 增加了窗口函数,每组最大 n 的每个问题都应该包括 MySQL 的版本。如果你可以使用 MySQL 8.0+,你应该使用窗口函数。 哇!窗口函数是我一直在寻找的答案!我使用 MariaDB 10.1.22,但我想我可以升级到 10.2,如果他们添加了对这些的支持。谢谢! 我将很快编辑这个问题以反映这里真正取得的成就。现在我改变了标题。 【参考方案1】:我想通了:
SELECT
listings.*,
max_p.product_id AS max_product_id
FROM listings
INNER JOIN (
SELECT DISTINCT max_external_id as external_id, pp3.id as product_id FROM
(SELECT MAX(p2.price) as max_price, l2.external_id as max_external_id
FROM products p2
INNER JOIN listings l2 ON l2.product_id = p2.id
GROUP BY l2.external_id) pp2
INNER JOIN
(SELECT p3.* FROM products p3 ) pp3
ON
pp2.max_price = pp3.price
ORDER BY pp3.price DESC
) AS max_p
ON max_p.external_id = listings.external_id
GROUP BY listings.external_id
在这里测试:
http://sqlfiddle.com/#!9/d58d665/53/0
【讨论】:
以上是关于如何在 MySQL < 8.0 中模拟窗口函数的主要内容,如果未能解决你的问题,请参考以下文章