我有一个 MySQL
dev_able
,其中包含数千种按其名称标识的产品,其中包含价格和可用性(以及其他值)随时间的变化。该表仅包含发生更改的日期。
我正在寻找一种有效的方法来选择特定日期可用的所有产品的最新结果 - 例如2016 年 1 月 1 日 – 即使给定日期可能没有该产品的条目。
SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
CREATE TABLE `dev_table` (`uid` int(11) NOT NULL, `Name` varchar(200) NOT NULL, `Date` date NOT NULL, `Available` tinyint(1) NOT NULL, `Price` decimal(5,2) NOT NULL, `Size` tinyint(1) NOT NULL);
ALTER TABLE `dev_table` ADD PRIMARY KEY (`uid`);
INSERT INTO `dev_table` (`uid`, `Name`, `Date`, `Available`, `Price`, `Size`) VALUES
(1, 'product A', '2000-01-01', 1, '123.33', 5), (2, 'product B', '2000-01-01', 1, '17.50', 1), (3, 'product C', '2003-06-01', 1, '578.25', 6), (4, 'product A', '2015-08-07', 1, '131.67', 2), (5, 'product D', '2016-01-01', 1, '8.02', 2),
(6, 'product C', '2016-01-01', 0, '478.72', 6), (7, 'product A', '2023-01-27', 1, '134.07', 5), (8, 'product B', '2023-09-01', 0, '12.01', 1);
+-----+------------+-------------+-----------+--------+------+
| uid | Name | Date | Available | Price | Size |
+-----+------------+-------------+-----------+--------+------+
| 1 | product A | 2000-01-01 | 1 | 123.33 | 5 |
| 2 | product B | 2000-01-01 | 1 | 17.50 | 1 |
| 3 | product C | 2003-06-12 | 1 | 578.25 | 6 |
| 4 | product A | 2015-08-07 | 1 | 131.67 | 2 |
| 5 | product D | 2015-01-01 | 0 | 8.02 | 2 |
| 6 | product C | 2016-01-01 | 0 | 478.72 | 6 |
| 7 | product A | 2023-01-27 | 1 | 134.07 | 5 |
| 8 | product B | 2023-09-01 | 0 | 12.01 | 1 |
我使用 2 个嵌套子查询来实现此目的:
SELECT * FROM `dev_table`
WHERE `uid` IN (
SELECT max(subquery1.`uid`) AS lastUid FROM `dev_table` AS subquery1
WHERE subquery1.`Date` <= '2016-01-01'
AND subquery1.`Name` NOT IN (
SELECT subquery2.`Name` FROM `dev_table` AS subquery2
WHERE subquery2.`Date` <= '2016-01-01'
AND subquery2.`Available` != 1
)
GROUP BY subquery1.`Name`
ORDER by lastUid DESC
);
这确实会按预期返回 uid 2、4 和 5 的行,这些行分别是产品 B、A 和 D 的最新条目,并且不会返回 uid 6,因为产品 D 在给定日期不可用。
但是,此解决方案在较大的表上效率较低。当添加更多标准(例如
MATCH (`Name`) AGAINST ('product' IN BOOLEAN MODE)
)时,情况会变得更糟。另外,ONLY_FULL_GROUP_BY
确实看起来有点过时了。
如何改进此查询?
您可以使用
HAVING
子句来排除那些至少具有一个不可用标志的产品,为此,我们必须仅选择具有全部可用产品的产品。总产品 'SUM(d.Available)
' 等于总产品 'COUNT(*)
' :
SELECT d.Name, max(d.uid) AS lastUid
FROM dev_table AS d
WHERE d.`Date` <= '2016-01-01'
GROUP BY d.Name
HAVING SUM(d.Available) = COUNT(*)