板凳-------Mysql cookbook学习 (十--7)

第8章:生成摘要

8.0 引言

sql 复制代码
mysql> select * from states order by name;
+----------------+--------+------------+----------+
| name           | abbrev | statehood  | pop      |
+----------------+--------+------------+----------+
| Alabama        | AL     | 1819-12-14 |  5039877 |
| Alaska         | AK     | 1959-01-03 |   732673 |
| Arizona        | AZ     | 1912-02-14 |  7276316 |
| Arkansas       | AR     | 1836-06-15 |  3025891 |
| California     | CA     | 1850-09-09 | 39237836 |
| Colorado       | CO     | 1876-08-01 |  5812069 |
| Connecticut    | CT     | 1788-01-09 |  3605597 |
| Delaware       | DE     | 1787-12-07 |  1003384 |
| Florida        | FL     | 1845-03-03 | 21781128 |
| Georgia        | GA     | 1788-01-02 | 10799566 |
| Hawaii         | HI     | 1959-08-21 |  1441553 |
| Idaho          | ID     | 1890-07-03 |  1900923 |
| Illinois       | IL     | 1818-12-03 | 12671469 |
| Indiana        | IN     | 1816-12-11 |  6805985 |
| Iowa           | IA     | 1846-12-28 |  3193079 |
| Kansas         | KS     | 1861-01-29 |  2934582 |
| Kentucky       | KY     | 1792-06-01 |  4509394 |
| Louisiana      | LA     | 1812-04-30 |  4624047 |
| Maine          | ME     | 1820-03-15 |  1372247 |
| Maryland       | MD     | 1788-04-28 |  6165129 |
| Massachusetts  | MA     | 1788-02-06 |  6984723 |
| Michigan       | MI     | 1837-01-26 | 10050811 |
| Minnesota      | MN     | 1858-05-11 |  5707390 |
| Mississippi    | MS     | 1817-12-10 |  2949965 |
| Missouri       | MO     | 1821-08-10 |  6168187 |
| Montana        | MT     | 1889-11-08 |  1104271 |
| Nebraska       | NE     | 1867-03-01 |  1963692 |
| Nevada         | NV     | 1864-10-31 |  3143991 |
| New Hampshire  | NH     | 1788-06-21 |  1388992 |
| New Jersey     | NJ     | 1787-12-18 |  9267130 |
| New Mexico     | NM     | 1912-01-06 |  2115877 |
| New York       | NY     | 1788-07-26 | 19835913 |
| North Carolina | NC     | 1789-11-21 | 10551162 |
| North Dakota   | ND     | 1889-11-02 |   774948 |
| Ohio           | OH     | 1803-03-01 | 11780017 |
| Oklahoma       | OK     | 1907-11-16 |  3986639 |
| Oregon         | OR     | 1859-02-14 |  4246155 |
| Pennsylvania   | PA     | 1787-12-12 | 12964056 |
| Rhode Island   | RI     | 1790-05-29 |  1095610 |
| South Carolina | SC     | 1788-05-23 |  5190705 |
| South Dakota   | SD     | 1889-11-02 |   895376 |
| Tennessee      | TN     | 1796-06-01 |  6975218 |
| Texas          | TX     | 1845-12-29 | 29527941 |
| Utah           | UT     | 1896-01-04 |  3337975 |
| Vermont        | VT     | 1791-03-04 |   645570 |
| Virginia       | VA     | 1788-06-25 |  8642274 |
| Washington     | WA     | 1889-11-11 |  7738692 |
| West Virginia  | WV     | 1863-06-20 |  1782959 |
| Wisconsin      | WI     | 1848-05-29 |  5895908 |
| Wyoming        | WY     | 1890-07-10 |   578803 |
+----------------+--------+------------+----------+
50 rows in set (0.02 sec)

8.1 使用count函数生成摘要

sql 复制代码
mysql> select count(*) from driver_log;
+----------+
| count(*) |
+----------+
|       10 |
+----------+
1 row in set (0.01 sec)

mysql> select count(*) from states;
+----------+
| count(*) |
+----------+
|       50 |
+----------+
1 row in set (0.00 sec)

mysql> select table_rows from information_schema.tables
    -> where table_schema='cookbook' and table_name = 'states';
+------------+
| TABLE_ROWS |
+------------+
|         50 |
+------------+
1 row in set (0.05 sec)

mysql> select count(*) from driver_log where miles > 200;
+----------+
| count(*) |
+----------+
|        4 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from driver_log where name = 'Suzi';
+----------+
| count(*) |
+----------+
|        2 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from states where statehood < '1900-01-01';
+----------+
| count(*) |
+----------+
|       45 |
+----------+
1 row in set (0.01 sec)

mysql> select count(*) from states where statehood < '1900-01-01';
+----------+
| count(*) |
+----------+
|       45 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from states
    -> where statehood between '1800-01-01' and '1899-12-31';
+----------+
| count(*) |
+----------+
|       29 |
+----------+
1 row in set (0.00 sec)

mysql> select
    -> count(if(dayofweek(trav_date)=7, 1, null)) as 'Saturday tripe',
    -> count(if(dayofweek(trav_date)=1, 1, null)) as 'Sunday trips'
    -> from driver_log;
+----------------+--------------+
| Saturday tripe | Sunday trips |
+----------------+--------------+
|              3 |            1 |
+----------------+--------------+
1 row in set (0.00 sec)

mysql> select
    -> count(if(dayofweek(trav_date) in (1, 7), 1, null)) as 'weekend trips',
    -> count(if(dayofweek(trav_date) in (1, 7), null, 1)) as 'weekday trips'
    -> from driver_log;
+---------------+---------------+
| weekend trips | weekday trips |
+---------------+---------------+
|             4 |             6 |
+---------------+---------------+
1 row in set (0.00 sec)

mysql> create view trip_summary_view as
    -> select
    -> count(if(dayofweek(trav_date) in(1, 7), 1, null)) as 'weekend trips',
    -> count(if(dayofweek(trav_date) in(1, 7), null, 1)) as 'weekday trips'
    -> from driver_log;
Query OK, 0 rows affected (0.03 sec)

mysql> select * from trip_summary_view;
+---------------+---------------+
| weekend trips | weekday trips |
+---------------+---------------+
|             4 |             6 |
+---------------+---------------+
1 row in set (0.01 sec)

8.2 使用min()和max()函数生成摘要

sql 复制代码
mysql> select
    -> min(t) as earliest, max(t) as latest,
    -> min(size) as smallest, max(size) as largest
    -> from mail;
+---------------------+---------------------+----------+---------+
| earliest            | latest              | smallest | largest |
+---------------------+---------------------+----------+---------+
| 2006-05-11 10:15:08 | 2006-05-19 22:21:51 |      271 | 2394482 |
+---------------------+---------------------+----------+---------+
1 row in set (0.01 sec)

mysql> select
    -> min(miles) as shortest, max(miles) as longest
    -> from driver_log;
+----------+---------+
| shortest | longest |
+----------+---------+
|       79 |     502 |
+----------+---------+
1 row in set (0.00 sec)

mysql> select
    -> min(pop) as 'fewest people', max(pop) as 'most people'
    -> from states;
+---------------+-------------+
| fewest people | most people |
+---------------+-------------+
|        578803 |    39237836 |
+---------------+-------------+
1 row in set (0.00 sec)

mysql> select min(name), max(name) from states;
+-----------+-----------+
| min(name) | max(name) |
+-----------+-----------+
| Alabama   | Wyoming   |
+-----------+-----------+
1 row in set (0.00 sec)

mysql> select
    -> min(char_length(name)) as shortest,
    -> max(char_length(name)) as longest
    -> from states;
+----------+---------+
| shortest | longest |
+----------+---------+
|        4 |      14 |
+----------+---------+
1 row in set (0.00 sec)

8.3 使用sum()和avg()函数生成摘要

sql 复制代码
mysql> select
    -> sum(size) as 'total traffic',
    -> avg(size) as 'average message size'
    -> from mail;
+---------------+----------------------+
| total traffic | average message size |
+---------------+----------------------+
|       3798185 |          237386.5625 |
+---------------+----------------------+
1 row in set (0.00 sec)

mysql> select
    -> sum(miles) as 'total miles',
    -> avg(miles) as 'average_mile/day'
    -> from driver_log;
+-------------+------------------+
| total miles | average_mile/day |
+-------------+------------------+
|        2166 |         216.6000 |
+-------------+------------------+
1 row in set (0.00 sec)

mysql> select sum(pop) from states;
+-----------+
| sum(pop)  |
+-----------+
| 331223695 |
+-----------+
1 row in set (0.00 sec)

mysql> select t1 from time_val;
+----------+
| t1       |
+----------+
| 15:00:00 |
| 05:01:30 |
| 12:30:20 |
+----------+
3 rows in set (0.01 sec)

mysql> select sum(time_to_sec(t1)) as 'total seconds',
    -> sec_to_time(sum(time_to_sec(t1))) as 'total time'
    -> from time_val;
+---------------+------------+
| total seconds | total time |
+---------------+------------+
|        117110 | 32:31:50   |
+---------------+------------+
1 row in set (0.01 sec)

8.4 使用distinct函数消除重复

sql 复制代码
mysql> select distinct name from driver_log order by name;
+-------+
| name  |
+-------+
| Ben   |
| Henry |
| Suzi  |
+-------+
3 rows in set (0.00 sec)

mysql> select name from driver_log;
+-------+
| name  |
+-------+
| Ben   |
| Suzi  |
| Henry |
| Henry |
| Ben   |
| Henry |
| Suzi  |
| Henry |
| Ben   |
| Henry |
+-------+
10 rows in set (0.00 sec)

mysql> select count(distinct name) from driver_log;
+----------------------+
| count(distinct name) |
+----------------------+
|                    3 |
+----------------------+
1 row in set (0.00 sec)

mysql> select distinct srcuser, dstuser from mail
    -> order by srcuser, dstuser;
+---------+---------+
| srcuser | dstuser |
+---------+---------+
| barb    | barb    |
| barb    | tricia  |
| gene    | barb    |
| gene    | gene    |
| gene    | tricia  |
| phil    | barb    |
| phil    | phil    |
| phil    | tricia  |
| tricia  | gene    |
| tricia  | phil    |
+---------+---------+
10 rows in set (0.00 sec)

mysql> select count(distinct srcuser, dstuser) from mail;
+----------------------------------+
| count(distinct srcuser, dstuser) |
+----------------------------------+
|                               10 |
+----------------------------------+
1 row in set (0.00 sec)

mysql> select count(distinct hour(t)) from mail;
+-------------------------+
| count(distinct hour(t)) |
+-------------------------+
|                      12 |
+-------------------------+
1 row in set (0.00 sec)

mysql> select distinct hour(t) as hour from mail order by hour;
+------+
| hour |
+------+
|    7 |
|    8 |
|    9 |
|   10 |
|   11 |
|   12 |
|   13 |
|   14 |
|   15 |
|   17 |
|   22 |
|   23 |
+------+
12 rows in set (0.00 sec)

8.5 查找数值相关的最大值和最小值

sql 复制代码
mysql> select max(pop) from states;
+----------+
| max(pop) |
+----------+
| 39237836 |
+----------+
1 row in set (0.00 sec)

mysql> select max(pop), name from states where pop = max(pop);
ERROR 1111 (HY000): Invalid use of group function
mysql> set @max=(select max(pop) from states);
Query OK, 0 rows affected (0.01 sec)

mysql> select pop as 'highest population', name from states where  pop = @max;
+--------------------+------------+
| highest population | name       |
+--------------------+------------+
|           39237836 | California |
+--------------------+------------+
1 row in set (0.00 sec)

mysql> select pop as 'highest population', name from states
    -> where pop = (select max(pop) from states);
+--------------------+------------+
| highest population | name       |
+--------------------+------------+
|           39237836 | California |
+--------------------+------------+
1 row in set (0.00 sec)

mysql> select min(char_length(vtext)) from kjv;
+-------------------------+
| min(char_length(vtext)) |
+-------------------------+
|                      11 |
+-------------------------+
1 row in set (0.11 sec)

mysql> select bname, cnum, vnum, vtext from kjv
    -> where char_length(vtext) = (select min(char_length(vtext)) from kjv);
+-------+------+------+-------------+
| bname | cnum | vnum | vtext       |
+-------+------+------+-------------+
| John  |   11 |   35 | Jesus wept. |
+-------+------+------+-------------+
1 row in set (0.09 sec)

mysql> select * from t;
+------+
| val  |
+------+
| 3    |
| 100  |
| NULL |
| NULL |
| 9    |
+------+
5 rows in set (0.00 sec)

mysql> drop table if exists ts;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> create table ts select max(pop) as maxpop from states;
Query OK, 1 row affected (0.05 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> select states.* from states inner join ts on states.pop = ts.maxpop;
+------------+--------+------------+----------+
| name       | abbrev | statehood  | pop      |
+------------+--------+------------+----------+
| California | CA     | 1850-09-09 | 39237836 |
+------------+--------+------------+----------+
1 row in set (0.01 sec)

8.6 控制min()函数和max()函数的字符串大小写区分

sql 复制代码
mysql> use employees;
Database changed

mysql> show create table employees;
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                                                                                                                                           |
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| employees | CREATE TABLE `employees` (
  `emp_no` int NOT NULL,
  `birth_date` date NOT NULL,
  `first_name` varchar(14) NOT NULL,
  `last_name` varchar(16) NOT NULL,
  `gender` enum('M','F') NOT NULL,
  `hire_date` date NOT NULL,
  PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT
    ->     MAX(last_name COLLATE utf8mb4_bin) AS max_last_name,
    ->     MIN(last_name COLLATE utf8mb4_bin) AS min_last_name
    -> FROM employees;
+---------------+---------------+
| max_last_name | min_last_name |
+---------------+---------------+
| dAstous       | Aamodt        |
+---------------+---------------+
1 row in set (0.31 sec)

mysql> CREATE TABLE tb1 (
    ->     col_a INT(11) DEFAULT NULL,
    ->     col_b CHAR(10) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
    ->     col_c CHAR(10) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
    ->     col_d CHAR(10) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,
    ->     KEY col_a (col_a),
    ->     KEY col_b (col_b)
    -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> INSERT INTO tb1 (col_a, col_b, col_c, col_d) VALUES
    -> (1, 'Apple', 'Red', 'FRUIT'),
    -> (2, 'Banana', 'Yellow', 'FRUIT'),
    -> (3, 'Dog', 'Brown', 'ANIMAL'),
    -> (4, 'Sky', 'Blue', 'NATURE'),
    -> (5, 'Sun', 'Yellow', 'NATURE'),
    -> (6, 'Coffee', 'Black', 'DRINK'),
    -> (7, 'Snow', 'White', 'WEATHER'),
    -> (8, 'Cat', 'Gray', 'ANIMAL'),
    -> (9, 'Rose', 'Pink', 'FLOWER'),
    -> (10, 'Book', 'Green', 'OBJECT');
Query OK, 10 rows affected (0.01 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql> select * from tbl;
ERROR 1146 (42S02): Table 'employees.tbl' doesn't exist
mysql> show tables;
+----------------------+
| Tables_in_employees  |
+----------------------+
| current_dept_emp     |
| data_quality_monitor |
| data_quality_results |
| departments          |
| dept_emp             |
| dept_emp_latest_date |
| dept_manager         |
| employees            |
| news                 |
| salaries             |
| t                    |
| tb1                  |
| test                 |
| titles               |
+----------------------+
14 rows in set (0.00 sec)

mysql> SELECT * FROM tb1 ORDER BY col_a;
+-------+--------+--------+---------+
| col_a | col_b  | col_c  | col_d   |
+-------+--------+--------+---------+
|     1 | Apple  | Red    | FRUIT   |
|     2 | Banana | Yellow | FRUIT   |
|     3 | Dog    | Brown  | ANIMAL  |
|     4 | Sky    | Blue   | NATURE  |
|     5 | Sun    | Yellow | NATURE  |
|     6 | Coffee | Black  | DRINK   |
|     7 | Snow   | White  | WEATHER |
|     8 | Cat    | Gray   | ANIMAL  |
|     9 | Rose   | Pink   | FLOWER  |
|    10 | Book   | Green  | OBJECT  |
+-------+--------+--------+---------+
10 rows in set (0.00 sec)

mysql> -- 不区分大小写的查询(col_b列)
mysql> SELECT * FROM tb1 WHERE col_b = 'apple';
+-------+-------+-------+-------+
| col_a | col_b | col_c | col_d |
+-------+-------+-------+-------+
|     1 | Apple | Red   | FRUIT |
+-------+-------+-------+-------+
1 row in set (0.00 sec)

mysql> use cookbook;
Database changed
mysql> DROP TABLE IF EXISTS tb1;
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> CREATE TABLE tb1 (
    ->     col_a INT DEFAULT NULL,
    ->     col_b CHAR(10) CHARACTER SET gbk COLLATE gbk_chinese_ci DEFAULT NULL,
    ->     col_c CHAR(10) CHARACTER SET gbk COLLATE gbk_chinese_ci DEFAULT NULL,
    ->     col_d CHAR(10) CHARACTER SET gbk COLLATE gbk_bin DEFAULT NULL,
    ->     KEY (col_a),
    ->     KEY (col_b)
    -> ) ENGINE=MyISAM DEFAULT CHARSET=gbk;
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO tb1 (col_a, col_b, col_c, col_d) VALUES
    -> (1, 'Apple', 'Red', 'FRUIT'),
    -> (2, 'Banana', 'Yellow', 'FRUIT'),
    -> (3, 'Dog', 'Brown', 'ANIMAL'),
    -> (4, 'Sky', 'Blue', 'NATURE'),
    -> (5, 'Sun', 'Yellow', 'NATURE'),
    -> (6, 'Coffee', 'Black', 'DRINK'),
    -> (7, 'Snow', 'White', 'WEATHER'),
    -> (8, 'Cat', 'Gray', 'ANIMAL'),
    -> (9, 'Rose', 'Pink', 'FLOWER'),
    -> (10, 'Book', 'Green', 'OBJECT');
Query OK, 10 rows affected (0.01 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql> show create table tbl;
ERROR 1146 (42S02): Table 'cookbook.tbl' doesn't exist
mysql> SELECT * FROM tb1 ORDER BY col_a;
+-------+--------+--------+---------+
| col_a | col_b  | col_c  | col_d   |
+-------+--------+--------+---------+
|     1 | Apple  | Red    | FRUIT   |
|     2 | Banana | Yellow | FRUIT   |
|     3 | Dog    | Brown  | ANIMAL  |
|     4 | Sky    | Blue   | NATURE  |
|     5 | Sun    | Yellow | NATURE  |
|     6 | Coffee | Black  | DRINK   |
|     7 | Snow   | White  | WEATHER |
|     8 | Cat    | Gray   | ANIMAL  |
|     9 | Rose   | Pink   | FLOWER  |
|    10 | Book   | Green  | OBJECT  |
+-------+--------+--------+---------+
10 rows in set (0.00 sec)

mysql> SELECT
    ->     MIN(col_b COLLATE gbk_chinese_ci) AS min_val,
    ->     MAX(col_b COLLATE gbk_chinese_ci) AS max_val
    -> FROM tb1;
+---------+---------+
| min_val | max_val |
+---------+---------+
| Apple   | Sun     |
+---------+---------+
1 row in set (0.00 sec)

mysql> SELECT
    ->     MIN(col_b COLLATE gbk_bin) AS min_val_bin,
    ->     MAX(col_b COLLATE gbk_bin) AS max_val_bin
    -> FROM tb1;
+-------------+-------------+
| min_val_bin | max_val_bin |
+-------------+-------------+
| Apple       | Sun         |
+-------------+-------------+
1 row in set (0.00 sec)

mysql> INSERT INTO tb1 VALUES
    -> (11, 'apple', 'red', 'fruit'),
    -> (12, 'book', 'blue', 'object');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM tb1 WHERE col_b = 'Apple';
+-------+-------+-------+-------+
| col_a | col_b | col_c | col_d |
+-------+-------+-------+-------+
|     1 | Apple | Red   | FRUIT |
|    11 | apple | red   | fruit |
+-------+-------+-------+-------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM tb1 WHERE col_d = 'FRUIT' COLLATE gbk_bin;
+-------+--------+--------+-------+
| col_a | col_b  | col_c  | col_d |
+-------+--------+--------+-------+
|     1 | Apple  | Red    | FRUIT |
|     2 | Banana | Yellow | FRUIT |
+-------+--------+--------+-------+
2 rows in set (0.00 sec)

mysql> EXPLAIN SELECT * FROM tb1 WHERE col_b = 'Apple';
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key   | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | tb1   | NULL       | ref  | col_b         | col_b | 21      | const |    2 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT * FROM tb1 WHERE col_a = 5;
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key   | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | tb1   | NULL       | ref  | col_a         | col_a | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> SELECT col_a,
    ->        CONVERT(col_b USING utf8mb4) AS col_b_utf8,
    ->        col_d
    -> FROM tb1
    -> WHERE col_a < 5;
+-------+------------+--------+
| col_a | col_b_utf8 | col_d  |
+-------+------------+--------+
|     1 | Apple      | FRUIT  |
|     2 | Banana     | FRUIT  |
|     3 | Dog        | ANIMAL |
|     4 | Sky        | NATURE |
+-------+------------+--------+
4 rows in set (0.00 sec)

mysql> -- 测试索引边界
mysql> INSERT INTO tb1 VALUES
    -> (0, '0_test', 'color', 'TYPE'),
    -> (2147483647, 'z_test', 'color', 'TYPE');  -- INT最大值
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql>
mysql> -- 验证索引扫描
mysql> EXPLAIN SELECT * FROM tb1 WHERE col_a BETWEEN 1 AND 10;
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | tb1   | NULL       | range | col_a         | col_a | 5       | NULL |    9 |   100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

mysql> -- 混合排序规则查询
mysql> SELECT col_a, col_b
    -> FROM tb1
    -> WHERE col_b = 'apple' COLLATE gbk_bin;  -- 强制区分大小写
+-------+-------+
| col_a | col_b |
+-------+-------+
|    11 | apple |
+-------+-------+
1 row in set (0.00 sec)

mysql>
mysql> -- 与默认排序规则对比
mysql> SELECT col_a, col_b
    -> FROM tb1
    -> WHERE col_b = 'apple';  -- 不区分大小写
+-------+-------+
| col_a | col_b |
+-------+-------+
|     1 | Apple |
|    11 | apple |
+-------+-------+
2 rows in set (0.00 sec)

mysql> -- 创建大容量测试数据(约10万行)
mysql> INSERT INTO tb1
    -> SELECT
    ->     n+10,
    ->     CONCAT('item', n),
    ->     'color',
    ->     CASE WHEN n%2=0 THEN 'TYPE_A' ELSE 'TYPE_B' END
    -> FROM (
    ->     SELECT a.N + b.N*10 + c.N*100 + d.N*1000 + e.N*10000 AS n
    ->     FROM (SELECT 0 AS N UNION SELECT 1 UNION...SELECT 9) a,
    ->          (SELECT 0 AS N UNION...SELECT 9) b,
    ->          (SELECT 0 AS N UNION...SELECT 9) c,
    ->          (SELECT 0 AS N UNION...SELECT 9) d,
    ->          (SELECT 0 AS N UNION...SELECT 9) e
    ->     LIMIT 100000
    -> ) t;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '...SELECT 9) a,
         (SELECT 0 AS N UNION...SELECT 9) b,
         (SELECT 0 ' at line 9
mysql>
mysql> -- 索引效率测试
mysql> ANALYZE TABLE tb1;
+--------------+---------+----------+----------+
| Table        | Op      | Msg_type | Msg_text |
+--------------+---------+----------+----------+
| cookbook.tb1 | analyze | status   | OK       |
+--------------+---------+----------+----------+
1 row in set (0.01 sec)

mysql> EXPLAIN SELECT * FROM tb1 WHERE col_b LIKE 'item1%';
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | tb1   | NULL       | range | col_b         | col_b | 21      | NULL |    1 |   100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

生产环境建议
索引优化

ALTER TABLE tb1 MODIFY col_b CHAR(10) CHARACTER SET gbk COLLATE gbk_bin;
-- 重建索引以提高区分大小写查询性能
ALTER TABLE tb1 DROP INDEX col_b, ADD INDEX (col_b);
字符集统一

-- 建议全表使用utf8mb4(如果系统支持)
ALTER TABLE tb1 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs;
监控建议

-- 定期检查索引使用情况
SELECT index_name, rows_read
FROM information_schema.table_io_waits_summary_by_index_usage
WHERE object_schema = 'cookbook' AND object_name = 'tb1';

mysql> -- 查看表结构确认列名
mysql> DESCRIBE tb1;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| col_a | int      | YES  | MUL | NULL    |       |
| col_b | char(10) | YES  | MUL | NULL    |       |
| col_c | char(10) | YES  |     | NULL    |       |
| col_d | char(10) | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
4 rows in set (0.01 sec)

mysql>
mysql> -- 正确的最小/最大值查询(区分大小写)
mysql> SELECT
    ->     MIN(col_b COLLATE gbk_bin) AS min_value,
    ->     MAX(col_b COLLATE gbk_bin) AS max_value
    -> FROM tb1;
+-----------+-----------+
| min_value | max_value |
+-----------+-----------+
| 0_test    | z_test    |
+-----------+-----------+
1 row in set (0.00 sec)

mysql>
mysql> -- 不区分大小写的查询
mysql> SELECT
    ->     MIN(col_b) AS min_value_ci,  -- 默认使用gbk_chinese_ci
    ->     MAX(col_b) AS max_value_ci
    -> FROM tb1;
+--------------+--------------+
| min_value_ci | max_value_ci |
+--------------+--------------+
| 0_test       | z_test       |
+--------------+--------------+
1 row in set (0.00 sec)

8.7 将摘要划分为子群

sql 复制代码
mysql> select count(*) from mail;
+----------+
| count(*) |
+----------+
|       16 |
+----------+
1 row in set (0.00 sec)

mysql> select srcuser, count(*) from mail
    -> group by srcuser;
+---------+----------+
| srcuser | count(*) |
+---------+----------+
| barb    |        3 |
| tricia  |        2 |
| phil    |        5 |
| gene    |        6 |
+---------+----------+
4 rows in set (0.00 sec)

mysql> select srcuser,
    -> sum(size) as 'total bytes',
    -> avg(size) as ' bytes per message'
    -> from mail group by srcuser;
+---------+-------------+-------------------+
| srcuser | total bytes | bytes per message |
+---------+-------------+-------------------+
| barb    |      156696 |        52232.0000 |
| tricia  |     2589407 |      1294703.5000 |
| phil    |       18974 |         3794.8000 |
| gene    |     1033108 |       172184.6667 |
+---------+-------------+-------------------+
4 rows in set, 1 warning (0.00 sec)

mysql> select srcuser, srchost ,count(srcuser) from mail
    -> group by srcuser, srchost;
+---------+---------+----------------+
| srcuser | srchost | count(srcuser) |
+---------+---------+----------------+
| barb    | saturn  |              2 |
| tricia  | mars    |              1 |
| phil    | mars    |              3 |
| gene    | venus   |              2 |
| barb    | venus   |              1 |
| tricia  | saturn  |              1 |
| gene    | mars    |              2 |
| phil    | venus   |              2 |
| gene    | saturn  |              2 |
+---------+---------+----------------+
9 rows in set (0.00 sec)

mysql> select srcuser, max(size), max(t) from mail group by srcuser;
+---------+-----------+---------------------+
| srcuser | max(size) | max(t)              |
+---------+-----------+---------------------+
| barb    |     98151 | 2006-05-14 14:42:21 |
| tricia  |   2394482 | 2006-05-14 17:03:01 |
| phil    |     10294 | 2006-05-17 12:49:23 |
| gene    |    998532 | 2006-05-19 22:21:51 |
+---------+-----------+---------------------+
4 rows in set (0.00 sec)

mysql> select srcuser, dstuser, max(size) from mail group by srcuser,dstuser;
+---------+---------+-----------+
| srcuser | dstuser | max(size) |
+---------+---------+-----------+
| barb    | tricia  |     58274 |
| tricia  | gene    |    194925 |
| phil    | phil    |      1048 |
| gene    | barb    |      2291 |
| phil    | tricia  |      5781 |
| barb    | barb    |     98151 |
| tricia  | phil    |   2394482 |
| gene    | gene    |     23992 |
| gene    | tricia  |    998532 |
| phil    | barb    |     10294 |
+---------+---------+-----------+
10 rows in set (0.00 sec)

mysql> select name, max(miles) as 'longest trip'
    -> from driver_log group by name;
+-------+--------------+
| name  | longest trip |
+-------+--------------+
| Ben   |          152 |
| Suzi  |          502 |
| Henry |          300 |
+-------+--------------+
3 rows in set (0.00 sec)

mysql> SELECT name, trav_date, miles AS 'longest trip'
    -> FROM (
    ->     SELECT
    ->         name,
    ->         trav_date,
    ->         miles,
    ->         RANK() OVER (PARTITION BY name ORDER BY miles DESC) AS rnk
    ->     FROM driver_log
    -> ) t
    -> WHERE rnk = 1;
+-------+------------+--------------+
| name  | trav_date  | longest trip |
+-------+------------+--------------+
| Ben   | 2014-07-30 |          152 |
| Henry | 2014-07-29 |          300 |
| Suzi  | 2014-08-02 |          502 |
+-------+------------+--------------+
3 rows in set (0.00 sec)

mysql> SELECT d1.name, d1.trav_date, d1.miles AS 'longest trip'
    -> FROM driver_log d1
    -> JOIN (
    ->     SELECT name, MAX(miles) AS max_miles
    ->     FROM driver_log
    ->     GROUP BY name
    -> ) d2 ON d1.name = d2.name AND d1.miles = d2.max_miles;
+-------+------------+--------------+
| name  | trav_date  | longest trip |
+-------+------------+--------------+
| Ben   | 2014-07-30 |          152 |
| Henry | 2014-07-29 |          300 |
| Suzi  | 2014-08-02 |          502 |
+-------+------------+--------------+
3 rows in set (0.00 sec)

mysql> -- 临时禁用ONLY_FULL_GROUP_BY
mysql> SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
Query OK, 0 rows affected (0.01 sec)

mysql>
mysql> -- 执行原查询
mysql> SELECT name, trav_date, MAX(miles) AS 'longest trip'
    -> FROM driver_log
    -> GROUP BY name;
+-------+------------+--------------+
| name  | trav_date  | longest trip |
+-------+------------+--------------+
| Ben   | 2014-07-30 |          152 |
| Suzi  | 2014-07-29 |          502 |
| Henry | 2014-07-29 |          300 |
+-------+------------+--------------+
3 rows in set (0.00 sec)

mysql>
mysql> -- 恢复原设置
mysql> SET SESSION sql_mode=@@global.sql_mode;
Query OK, 0 rows affected (0.00 sec)
方案对比
方案	优点	缺点	适用场景
子查询	兼容性好,所有MySQL版本支持	SQL稍复杂	所有环境
窗口函数	语法简洁	需要MySQL 8.0+	新版MySQL
修改sql_mode	简单	违反SQL标准	临时分析

mysql> create table ttt
    -> select name, max(miles) as miles from driver_log group by name;
Query OK, 3 rows affected (0.05 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select d.name, d.trav_date, d.miles as 'longest trip'
    -> from driver_log as d inner join ttt using (name, miles) order by name;
+-------+------------+--------------+
| name  | trav_date  | longest trip |
+-------+------------+--------------+
| Ben   | 2014-07-30 |          152 |
| Henry | 2014-07-29 |          300 |
| Suzi  | 2014-08-02 |          502 |
+-------+------------+--------------+
3 rows in set (0.00 sec)

8.8 摘要与空值

sql 复制代码
mysql> select subject, test, score from expt order by subject, test;
+---------+------+-------+
| subject | test | score |
+---------+------+-------+
| Jane    | A    |    47 |
| Jane    | B    |    50 |
| Jane    | C    |  NULL |
| Jane    | D    |  NULL |
| Marvin  | A    |    52 |
| Marvin  | B    |    45 |
| Marvin  | C    |    53 |
| Marvin  | D    |  NULL |
+---------+------+-------+
8 rows in set (0.01 sec)

mysql> select subject,
    -> count(score) as n,
    -> sum(score) as total,
    -> avg(score) as average,
    -> min(score) as lowest,
    -> max(score) as highest
    -> from expt group by subject;
+---------+---+-------+---------+--------+---------+
| subject | n | total | average | lowest | highest |
+---------+---+-------+---------+--------+---------+
| Jane    | 2 |    97 | 48.5000 |     47 |      50 |
| Marvin  | 3 |   150 | 50.0000 |     45 |      53 |
+---------+---+-------+---------+--------+---------+
2 rows in set (0.00 sec)
相关推荐
Hello.Reader3 小时前
Redis 延迟监控深度指南
数据库·redis·缓存
ybq195133454313 小时前
Redis-主从复制-分布式系统
java·数据库·redis
DKPT5 小时前
Java桥接模式实现方式与测试方法
java·笔记·学习·设计模式·桥接模式
好奇的菜鸟6 小时前
如何在IntelliJ IDEA中设置数据库连接全局共享
java·数据库·intellij-idea
tan180°6 小时前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
满昕欢喜7 小时前
SQL Server从入门到项目实践(超值版)读书笔记 20
数据库·sql·sqlserver
DuelCode7 小时前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis
好好研究7 小时前
学习栈和队列的插入和删除操作
数据结构·学习
幽络源小助理7 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
Hello.Reader8 小时前
Redis 延迟排查与优化全攻略
数据库·redis·缓存