【发布时间】: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。