微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

仅将某些行与GROUP BY分组

如何解决仅将某些行与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_idNULL值的 *所有 项目都具有价值, 并且
  • *每个组中的 *一项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 举报,一经查实,本站将立刻删除。