获取给定组的每种产品的最低价格
Posted
技术标签:
【中文标题】获取给定组的每种产品的最低价格【英文标题】:Get minimum price of each product for given group(s) 【发布时间】:2020-03-05 08:15:56 【问题描述】:我有这些简单的表格:
products
+----+------+---------+
| id | code | details |
+----+------+---------+
| 1 | P01 | ... |
| 2 | P02 | ... |
| 3 | P03 | ... |
+----+------+---------+
prices
+----+---------------+-------------+--------+------------+------------+
| id | customerGroup | productCode | price | date | endDate |
+----+---------------+-------------+--------+------------+------------+
| 1 | DEFAULT | P01 | 1.2500 | 2018-01-01 | NULL |
| 2 | DEFAULT | P02 | 1.4000 | 2018-01-01 | NULL |
| 3 | DEFAULT | P03 | 2.0000 | 2018-01-01 | NULL |
| 4 | DEFAULT | P01 | 1.3000 | 2018-07-01 | NULL |
| 5 | BLUE | P01 | 1.3100 | 2019-01-01 | NULL |
| 6 | BLUE | P02 | 0.9000 | 2019-01-01 | 2019-05-01 |
| 7 | BLUE | P03 | 2.0000 | 2019-09-01 | NULL |
| 8 | DEFAULT | P01 | 1.3200 | 2019-10-01 | NULL |
| 9 | GREEN | P01 | 0.5000 | 2019-10-01 | NULL |
| 10 | GREEN | P02 | 0.6000 | 2019-10-01 | NULL |
| 11 | GREEN | P03 | 0.7000 | 2019-10-01 | NULL |
+----+---------------+-------------+--------+------------+------------+
逻辑
prices
是一个历史表。
每一行代表一个产品和一个客户组的price
记录。
endDate = NULL
表示price
条目在date
和永恒之间有效(除非出现以下情况)。
如果同一 customerGroup
和 productCode
的 price
记录具有较新的匹配 date
,它会覆盖较旧的记录 - 即使 price
更高。
相同productCode
和匹配日期的最小price
值将获胜;只要customerGroup
与给定的组匹配。
目标 1
要获得可能的最低价格记录:
对于BLUE
和DEFAULT
组的成员
产品P01
日期2019-10-01
SELECT
pp.*
FROM prices AS pp
JOIN (
SELECT customerGroup, MAX(date) AS maxDate
FROM prices AS pp
WHERE productCode = 'P01'
GROUP BY customerGroup
) AS eachRow ON (pp.customerGroup = eachRow.customerGroup AND pp.date = eachRow.maxDate)
WHERE
pp.productCode = 'P01'
AND FIND_IN_SET(pp.customerGroup, 'DEFAULT,BLUE') > 0
AND ((pp.endDate IS NULL AND '2019-10-01' >= pp.date) OR (pp.endDate IS NOT NULL AND ('2019-10-01' BETWEEN pp.date AND pp.endDate)))
GROUP BY pp.customerGroup
ORDER BY pp.price ASC
LIMIT 1;
这会返回正确/预期的单一结果:
+----+---------------+-------------+--------+------------+------------+
| id | customerGroup | productCode | price | date | endDate |
+----+---------------+-------------+--------+------------+------------+
| 5 | BLUE | P01 | 1.3100 | 2019-01-01 | NULL |
+----+---------------+-------------+--------+------------+------------+
目标 2(问题)
如何一次性获取products
中每种产品的最低价格记录?
结果应该是:
+----+---------------+-------------+--------+------------+------------+
| id | customerGroup | productCode | price | date | endDate |
+----+---------------+-------------+--------+------------+------------+
| 2 | DEFAULT | P02 | 1.4000 | 2018-01-01 | NULL |
| 5 | BLUE | P01 | 1.3100 | 2019-01-01 | NULL |
| 7 | BLUE | P03 | 2.0000 | 2019-09-01 | NULL |
+----+---------------+-------------+--------+------------+------------+
注意事项:
我正在寻找一种在外部查询中不使用GROUP_CONCAT
的方法。
MIN
+ GROUP BY
使用不是解决方案,因为它不会正确返回所有必要的字段,例如 customerGroup
和 date
...
这是SQL Fiddle。
【问题讨论】:
您可以将FIND_IN_SET(pp.customerGroup, 'DEFAULT,BLUE') > 0
替换为pp.customerGroup IN ('DEFAULT', 'BLUE')
。它更简单、更标准,并且性能可能更好。
您使用的是什么版本的 mysql?在 MySQL 8 中添加的Window functions 将使这更容易。
不幸的是 MySQL 5.7。
【参考方案1】:
目标 2(问题) 如何一次获取 products 中每个产品的最低价格记录?
答案是:
Select p.productcode, min(p.price)
from prices p
left join products prd on p.productcode = prd.code
Group by p.productcode
输出: P01 0.5 P02 0.6 P03 0.7
但是你的请求结果是按id分组的,所以不能按产品显示最低价格。您显示的结果中的实际数据实际上不是最低价格吗? (这令人困惑)。
【讨论】:
谢谢。但min
+ group by
不会返回所有必填字段。结果中的最低价格是错误的。这些价格适用于GREEN
组。请阅读 logic 部分中的问题详情。【参考方案2】:
查询第二个问题
SELECT MAX(pp.customerGroup) as CustomerGroup, MAX(pp.ProductCode) as ProductCode , MIN(pp.price) as Price FROM Prices as pp
INNER JOIN Products as pro
on pp.PRoductCode = pro.Code
GROUP BY pp.customerGroup
ORDER BY pp.customerGroup;
如果我错了,请纠正我,我会相应地更新答案..
【讨论】:
如果这是正确的,那么将回答你的第一个问题。以上是关于获取给定组的每种产品的最低价格的主要内容,如果未能解决你的问题,请参考以下文章