当前位置: 首页 > 面试题库 >

仅将某些行与GROUP BY分组

郎言
2023-03-14
问题内容

施玛

我在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', NULL, 20),
(3, 'Item C', NULL, 30),
(4, 'Item D', 1,    40),
(5, 'Item E', 2,    50),
(6, 'Item F', 2,    60),
(7, 'Item G', 2,    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, name, 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, name, group_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中有效。


问题答案:

为了提高性能,还为添加了组合索引(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;

作为偶然的副作用,此查询在我需要包含与 AND 相等的 AND的 所有 记录中包含最低价格的每个组中的 一项的情况下起作用。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转储。然后,我可以使用转储将那几行上载到另一个数据库中。我拥有的代码正在运行,但是它会转储所有内容。我怎样才能使mysqldump只转储表的某些行? 这是我的代码: 问题答案: 只需解决您的选择。它应该是有效的SQL WHERE子句,例如: 您将列名放在引号之外。

  • 问题内容: 我喜欢Django,但对于特定的应用程序,我只想使用其中的一部分,但是我对Django在内部的工作方式还不够熟悉,因此也许有人可以为我指明正确的方向查看。 具体来说,我想使用: 模型和数据库抽象 该缓存API,但我想通过缓存来避免数据库查询,而不是HTML生成,并且由于在Django的缓存框架适用于后者,我不 知道是否还没有这真的合适。 我不会使用: Templating urlcon

  • 问题内容: 如果我有一些代码,例如 并且输入文件包含成对的行,我该如何做,以便仅导入每行的第一行?因此,换句话说,每条奇数行都只有?谢谢 问题答案: 您可能想考虑使用来简化奇数行()的过滤。或者在另一种方法中,如果您使用的是JDK7,则可以使用该方法,并在迭代时再次过滤奇数。

  • 问题内容: 我想创建JTextField,输入字符限于“ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYWZZ0123456789 +&@#/%?=〜_- |!:,。;”之类的输入字符。所以我尝试覆盖 但这不是我想要的,因为用户无法再按ctrl-c ctrl-v ctrl-x …所以我添加了 到if条件,但现在用户可以粘贴不适当的输入,即’(’

  • 问题内容: 我有一个现有的网站,上面有很多用表格布置的旧页面和表格,我正尝试逐步过渡到CSS。我想使用Twitter Bootstrap样式表-特别是表单样式- 但仅在我明确要求它们的页面部分中使用。例如,我可能将整个表单围绕在div中,如下所示: 我希望所有其他形式保持与现在相同,因为我将无法同时更改所有形式。有没有简单的方法可以做到这一点?我可以遍历Bootstrap CSS中的每种样式,并添

  • 问题内容: 我正在尝试创建一个(sqlite)查询,该查询将执行GROUP BY,但不会将任何值’unknown’分组。例如,我有表: 使用正确的查询并带有“ GROUP BY名称,parent_id,school_id”,我需要返回以下行: 任何帮助将不胜感激。谢谢! 问题答案: 您很难用一个语句来完成此操作,但是可以使用两个语句的结果 所有的名单 ,但 添加()全部列表 SQL语句 请注意,我