如何解决仅将某些行与GROUP BY分组
为了提高性能,还为添加了组合索引(group_id, price, id)
。
SELECT a.id, a.name, a.group_id, a.price
FROM items a
LEFT JOIN items b
ON a.group_id = b.group_id
AND (a.price > b.price OR (a.price = b.price and a.id > b.id))
WHERE b.price is NULL;
作为偶然的副作用,此查询在我需要包含与 相等的 记录中包含最低价格的每个组中的 情况下起作用。group_id``NULL
+----+--------+----------+-------+
| id | name | group_id | price |
+----+--------+----------+-------+
| 1 | Item A | NULL | 10.00 |
| 2 | Item B | NULL | 20.00 |
| 3 | Item C | NULL | 30.00 |
| 4 | Item D | 1 | 40.00 |
| 5 | Item E | 2 | 50.00 |
+----+--------+----------+-------+
+----+-------------+-------+------+-------------------------------+--------------------+---------+----------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-------------------------------+--------------------+---------+----------------------------+------+--------------------------+
| 1 | SIMPLE | a | ALL | NULL | NULL | NULL | NULL | 7 | |
| 1 | SIMPLE | b | ref | PRIMARY,id,items_group_id_idx | items_group_id_idx | 5 | agi_development.a.group_id | 1 | Using where; Using index |
+----+-------------+-------+------+-------------------------------+--------------------+---------+----------------------------+------+--------------------------+
解决方法
施玛
我在MySQL数据库中进行了以下设置:
CREATE TABLE items (
id SERIAL,name VARCHAR(100),group_id INT,price DECIMAL(10,2),KEY items_group_id_idx (group_id),PRIMARY KEY (id)
);
INSERT INTO items VALUES
(1,'Item A',NULL,10),(2,'Item B',20),(3,'Item C',30),(4,'Item D',1,40),(5,'Item E',2,50),(6,'Item F',60),(7,'Item G',70);
问题
我需要选择:
- *具有
group_id
该NULL
值的 *所有 项目都具有价值, 并且- *每个组中的 *一项
group_id
以 最低的 价格确定。
预期成绩
+----+--------+----------+-------+
| id | name | group_id | price |
+----+--------+----------+-------+
| 1 | Item A | NULL | 10.00 |
| 2 | Item B | NULL | 20.00 |
| 3 | Item C | NULL | 30.00 |
| 4 | Item D | 1 | 40.00 |
| 5 | Item E | 2 | 50.00 |
+----+--------+----------+-------+
可能的解决方案1: 两个查询UNION ALL
SELECT id,name,group_id,price FROM items
WHERE group_id IS NULL
UNION ALL
SELECT id,MIN(price) FROM items
WHERE group_id IS NOT NULL
GROUP BY group_id;
/* EXPLAIN */
+----+--------------+------------+------+--------------------+--------------------+---------+-------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+------+--------------------+--------------------+---------+-------+------+----------------------------------------------+
| 1 | PRIMARY | items | ref | items_group_id_idx | items_group_id_idx | 5 | const | 3 | Using where |
| 2 | UNION | items | ALL | items_group_id_idx | NULL | NULL | NULL | 7 | Using where; Using temporary; Using filesort |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | |
+----+--------------+------------+------+--------------------+--------------------+---------+-------+------+----------------------------------------------+
但是,不希望有两个查询,因为WHERE
子句中的条件会更复杂,而且我需要对最终结果进行排序。
可能的解决方案2: GROUP
BY
关于表达式(参考)
SELECT id,MIN(price) FROM items
GROUP BY CASE WHEN group_id IS NOT NULL THEN group_id ELSE RAND() END;
/* EXPLAIN */
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
| 1 | SIMPLE | items | ALL | NULL | NULL | NULL | NULL | 7 | Using temporary; Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
解决方案2似乎更快速,更易于使用,但是我想知道在性能方面是否有更好的方法。
更新 :
根据@axiac引用的文档,此查询在SQL92和更早版本中是非法的,并且仅在MySQL中有效。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。