MySQL分组数据和子查询

分组数据

创建分组

mysql> SELECT vend_id,COUNT(*) AS num_prods
	   FROM products 
	   GROUP BY vend_id;
+---------+-----------+
| vend_id | num_prods |
+---------+-----------+
|    1001 |         3 |
|    1002 |         2 |
|    1003 |         7 |
|    1005 |         2 |
+---------+-----------+
4 rows in set (0.01 sec)
  • 上面的SELECT语句指定了两个列,vend_id包含产品供应商的ID,
    num_prods为计算字段(用COUNT(*)函数建立)。GROUP BY子句指
    示MySQL按vend_id排序并分组数据。这导致对每个vend_id而不是整个表
    计算num_prods一次。从输出中可以看到,供应商1001有3个产品,供应商
    1002有2个产品,供应商1003有7个产品,而供应商1005有2个产品。
  • 因为使用了GROUP BY,就不必指定要计算和估值的每个组了。系统
    会自动完成。GROUP BY子句指示MySQL分组数据,然后对每个组而不是
    整个结果集进行聚集。
  • 在具体使用GROUP BY子句前,需要知道一些重要的规定。
    • GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套,
      为数据分组提供更细致的控制。
    • 如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上
      进行汇总。换句话说,在建立分组时,指定的所有列都一起计算
      (所以不能从个别的列取回数据)。
    • GROUP BY子句中列出的每个列都必须是检索列或有效的表达式
      (但不能是聚集函数)。如果在SELECT中使用表达式,则必须在
      GROUP BY子句中指定相同的表达式。不能使用别名。
    • 除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子
      句中给出。
    • 如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列
      中有多行NULL值,它们将分为一组。
    • GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。

过滤分组

  • HAVING非常类似于WHERE。事实上,目前为止所学过的所有类型的WHERE子句都可以用HAVING来替代。唯一的差别是WHERE过滤行,而HAVING过滤分组。
mysql> SELECT cust_id,COUNT(*) AS orders 
	   FROM orders 
	   GROUP BY cust_id 
	   HAVING COUNT(*)>=2;
+---------+--------+
| cust_id | orders |
+---------+--------+
|   10001 |      2 |
+---------+--------+
1 row in set (0.00 sec)
  • HAVING和WHERE的差别 这里有另一种理解方法,WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重要的区别,WHERE排除的行不包括在分组中。这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。

分组和排序

mysql> SELECT order_num,SUM(quantity*item_price)AS ordertotal 
	   FROM orderitems
 	   GROUP BY order_num 
 	   HAVING SUM(quantity*item_price)>=50 
 	   ORDER BY ordertotal;
+-----------+------------+
| order_num | ordertotal |
+-----------+------------+
|     20006 |      55.00 |
|     20008 |     125.00 |
|     20005 |     149.87 |
|     20007 |    1000.00 |
+-----------+------------+
4 rows in set (0.01 sec)
  • 它检索总计订单价格大于等于50的订单的订单号和总计订单价格,按总计订单价格排序输出。

SELECT 子句顺序

字句 说明 是否必须使用
SELECT 要返回的列或表达式
FORM 从中检索数据的表 仅在从表选择数据时使用
WHERE 行级过滤
GROUP BY 分组说明 仅在按组计算聚集时使用
HAVING 组级过滤
ORDER BY 输出排序顺序
LIMIT 要检索的行数

子查询

  • 子查询就是把一条SELECT语句返回的结果用于另一条SELECT语句的WHERE子句。

利用子查询进行过滤

mysql> SELECT order_num 
	   FROM orderitems
       WHERE prod_id='TNT2';
+-----------+
| order_num |
+-----------+
|     20005 |
|     20007 |
+-----------+
2 rows in set (0.01 sec)

mysql> SELECT cust_id 
	   FROM orders 
	   where order_num IN(20005,20007);
+---------+
| cust_id |
+---------+
|   10001 |
|   10004 |
+---------+
2 rows in set (0.00 sec)

mysql> SELECT cust_id
	   FROM orders 
	   where order_num IN(SELECT order_num
                          FROM orderitems 
                          WHERE prod_id='TNT2');
+---------+
| cust_id |
+---------+
|   10001 |
|   10004 |
+---------+
2 rows in set (0.01 sec)
  • 在SELECT语句中,子查询总是从内向外处理。在处理上面的SELECT语句时,MySQL实际上执行了两个操作。首先,它执行下面的查询:
SELECT order_num FROM orderitems WHERE prod_id='TNT2';
  • 此查询返回两个订单号:20005和20007。然后,这两个值以IN操作符要求的逗号分隔的格式传递给外部查询的WHERE子句。外部查询变成:
SELECT cust_id FROM orders where order_num IN(20005,20007);
  • 可以看到,输出是正确的并且与前面硬编码WHERE子句所返回的值相同。

  • 列必须匹配 在WHERE子句中使用子查询(如这里所示),应该保证SELECT语句具有与WHERE子句中相同数目的列。通常,子查询将返回单个列并且与单个列匹配,但如果需要也可以使用多个列。

  • 虽然子查询一般与IN操作符结合使用,但也可以用于测试等于(=)、不等于(<>)等。

作为计算字段使用子查询

mysql> SELECT COUNT(*) AS orders FROM orders WHERE cust_id=10001;
+--------+
| orders |
+--------+
|      2 |
+--------+
1 row in set (0.00 sec)
  • 为了对每个客户执行COUNT()计算,应该将COUNT()作为一个子查询。请看下面的代码:
mysql> SELECT cust_name,cust_state,(SELECT COUNT(*) 
                                    FROM orders 
                                    WHERE orders.cust_id=customers.cust_id) AS orders 
       FROM customers 
       ORDER BY cust_name;
+----------------+------------+--------+
| cust_name      | cust_state | orders |
+----------------+------------+--------+
| Coyote Inc.    | MI         |      2 |
| E Fudd         | IL         |      1 |
| Mouse House    | OH         |      0 |
| Wascals        | IN         |      1 |
| Yosemite Place | AZ         |      1 |
+----------------+------------+--------+
5 rows in set (0.01 sec)
  • 这 条 SELECT 语句对 customers 表中每个客户返回 3 列 :cust_name、cust_state和orders。orders是一个计算字段,它是由圆括号中的子查询建立的。该子查询对检索出的每个客户执行一次。在此例子中,该子查询执行了5次,因为检索出了5个客户。

  • 子查询中的WHERE子句与前面使用的WHERE子句稍有不同,因为它使用了完全限定列名(在第4章中首次提到)。下面的语句告诉SQL比较orders表中的cust_id与当前正从customers表中检索的cust_id:

    WHERE orders.cust_id=customers.cust_id
    
  • 相关子查询(correlated subquery) 涉及外部查询的子查询。这种类型的子查询称为相关子查询。

posted @ 2020-06-18 16:34  放飞梦想C  阅读(365)  评论(0编辑  收藏  举报